把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如,數組 [3,4,5,1,2] 爲 [1,2,3,4,5] 的一個旋轉,該數組的最小值爲1。
示例 1:
輸入:[3,4,5,1,2]
輸出:1
示例 2:
輸入:[2,2,2,0,1]
輸出:0
我尋思這不就是找最小值嗎?
但是仔細看題還是也有一點點區別,這個數組是半有序,[3,4,5,1,2]這樣子,總體無序前後兩端都是有序的,所以有一些特殊的方法。
解法一:暴力求解
class Solution {
public int minArray(int[] numbers) {
for(int i=0;i<numbers.length-1;i++)
{
if(numbers[i]>numbers[i+1])
return numbers[i+1];
}
return numbers[0];
}
}
解法二:二分法
- 循環二分: 設置 i, j 指針分別指向 numbers 數組左右兩端,m = (i + j) / 2 ,爲每次二分的中點( “//” 代表向下取整除法,因此恆有 i <=m <j ),可分爲以下三種情況:
- 當 numbers[m] > numbers[j]時: m 一定在 左排序數組 中,即旋轉點 x 一定在 [m+1,j] 閉區間內,因此執行 i = m + 1;
- 當 numbers[m] < numbers[j] 時: m 一定在 右排序數組 中,即旋轉點 x 一定在[i,m] 閉區間內,因此執行 j = m;
- 當 numbers[m] == numbers[j] 時: 無法判斷 m 在哪個排序數組中,即無法判斷旋轉點 x 在 [i, m]還是 [m + 1, j]區間中。
- 解決方案: 執行 j = j - 1 縮小判斷範圍 (分析見以下內容) 。
- 返回值: 當 i = j 時跳出二分循環,並返回 numbers[i] 即可。
class Solution {
public int minArray(int[] numbers) {
int i = 0, j = numbers.length - 1;
while (i < j) {
int m = (i + j) / 2;
if (numbers[m] > numbers[j]) i = m + 1;
else if (numbers[m] < numbers[j]) j = m;
else j--;
}
return numbers[i];
}
}