劍指06.旋轉陣列的最小數字
阿新 • • 發佈:2020-08-05
題目描述
把一個數組最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。輸入一個非遞減排序的陣列的一個旋轉,輸出旋轉陣列的最小元素。
例如陣列{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),這是最容易想到的方案,但這樣沒用到旋轉陣列的特性,肯定不行!!- 和二分查詢一樣,用兩個指標分別指向陣列的第一個元素和最後一個元素。
- 找到陣列的中間元素,如果中間元素大於第一個指標指向的元素,則中間元素位於前面的遞增子陣列,此時最小元素位於中間元素的後面,我們讓第一個指標left指向該中間元素;如果中間元素小於第二個指標指向的元素,則中間元素位於後面的遞增子陣列,此時最小元素位於中間元素的前面,我們讓第二個指標right指向中間元素。
- 這樣查詢範圍會縮小到原來的一半,第一個指標總是指向前面遞增陣列的元素,第二個指標總是指向後面的遞增陣列的元素。最終,第一個指標將指向前面子陣列的最後一個元素,而第二個指標會指向後面子陣列的第一個元素(也就是最小的元素
解法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; //如果旋轉陣列是排序陣列本身,直接返回第一個數字Note: 關於取中間值為什麼是left+(right-left)/2,而不是直接(right+left)/2? 答:第一種方式更穩定!!如果兩個數都很大,相加將導致溢位。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; } }
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