1. 程式人生 > 實用技巧 >劍指06.旋轉陣列的最小數字

劍指06.旋轉陣列的最小數字

題目描述

把一個數組最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。
輸入一個非遞減排序的陣列的一個旋轉,輸出旋轉陣列的最小元素。
例如陣列{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該陣列的最小值為1。
NOTE:給出的所有元素都大於0,若陣列大小為0,請返回0。

案例

{3 4 5 1 2} (一般情況)

{1 2 3 4 5} (特例,前面0個元素搬到後面,即已經排好序的情況)

{1 0 1 1 1} / {1 1 1 0 1}(特例,都可以看成遞增排序陣列{0 1 1 1 1 }的旋轉)

分析

遍歷整個陣列找出其中最小的數,複雜度為O(n),這是最容易想到的方案,但這樣沒用到旋轉陣列的特性,肯定不行!!
本題考查二分查詢。旋轉之後的陣列實際上可以劃分成兩個有序的子陣列:前面子陣列的元素都大於後面子陣列中的元素,而且最小的元素剛好是這兩個子陣列的分界線。
  1. 和二分查詢一樣,用兩個指標分別指向陣列的第一個元素和最後一個元素。
  2. 找到陣列的中間元素,如果中間元素大於第一個指標指向的元素,則中間元素位於前面的遞增子陣列,此時最小元素位於中間元素的後面,我們讓第一個指標left指向該中間元素;如果中間元素小於第二個指標指向的元素,則中間元素位於後面的遞增子陣列,此時最小元素位於中間元素的前面,我們讓第二個指標right指向中間元素。
  3. 這樣查詢範圍會縮小到原來的一半,第一個指標總是指向前面遞增陣列的元素,第二個指標總是指向後面的遞增陣列的元素。最終,第一個指標將指向前面子陣列的最後一個元素,而第二個指標會指向後面子陣列的第一個元素(也就是最小的元素
    ),即它們最終指向兩個相鄰的元素,迴圈結束。

解法1

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if (array.length == 0)
            return 0;
        int indexLeft = 0;
        int indexRight = array.length - 1;
        int indexMid = indexLeft; //如果旋轉陣列是排序陣列本身,直接返回第一個數字
while (array[indexLeft] >= array[indexRight]){ if (indexRight - indexLeft == 1){ indexMid = indexRight; break; } indexMid = indexLeft + (indexRight - indexLeft) / 2; //對於特例[1,0,1,1,1]和[1,1,1,0,1] //當兩個指標指向的數字及它們中間的數字三者相同的時候; //無法判斷中間的數字是位於前面的子陣列還是後面的子陣列,只能採用順序查詢的方法 if (array[indexMid] == array[indexLeft] && array[indexMid] == array[indexRight]){ return minInOrder(array, indexLeft, indexRight); } if (array[indexMid] >= array[indexLeft]){ indexLeft = indexMid; } if (array[indexMid] <= array[indexRight]){ indexRight = indexMid; } } return array[indexMid]; } public int minInOrder(int[] array, int indexLeft, int indexRight){ int result = array[indexLeft]; for (int i = indexLeft + 1; i <= indexRight; i++){ if (array[i] < result) result = array[i]; } return result; } }

Note: 關於取中間值為什麼是left+(right-left)/2,而不是直接(right+left)/2? 答:第一種方式更穩定!!如果兩個數都很大,相加將導致溢位。
int x = 1999999998;
int y = 1999999998;
int mid = (x+y) / 2;
int mid2 = x + (y-x) / 2;
System.out.println(mid); //-147483650
System.out.println(mid2); //1999999998