問題描述:
假設按照升序排序的數組在預先未知的某個點上進行了旋轉。
( 例如,數組 [0,1,2,4,5,6,7]
可能變爲 [4,5,6,7,0,1,2]
)。
請找出其中最小的元素。
你可以假設數組中不存在重複元素。
示例 1:
輸入: [3,4,5,1,2] 輸出: 1
示例 2:
輸入: [4,5,6,7,0,1,2] 輸出: 0
法一:
如下所示,編寫較爲複雜。
我們在旋轉數組中找到一個最小元素的衝要條件是他兩邊的元素都比他大,或者是一個遞增序列的第一個元素。
這個明顯是基於旁邊元素的二分查找,按照特殊情況和普通情況來處理。
這裏特別要注意遞增序列。
因爲遞增序列答案在數組首部,然而我們這個方法會把我們的指針往後引。所以要特別判斷、
class Solution {
public:
int Find(vector<int> &a, int l, int r) {
// 沒找到
if (l > r) return -1;
// 特殊情況
if (l == r) return l; // 只有一個元素
if (l == r - 1) return a[l] > a[r]? r : l; // 只有兩個元素
// 正常處理
int m = l + (r - l) / 2;
if (a[m - 1] > a[m] && a[m] < a[m + 1]) return m;
int result1 = -1, result2 = -1;
if (a[m] > a[0]) result1 = Find(a, m + 1, r); // 在左半邊
if (a[m] < a[a.size() - 1]) result2 = Find(a, l, m - 1); // 在右半邊
if (result1 != -1 && result2 != -1) {
return 0;
} else {
return result1 == -1? result2 : result1;
}
}
int findMin(vector<int>& nums) {
return nums[Find(nums, 0, nums.size() - 1)];
}
};
法二:
使用左閉右也閉的方法。
在while循環內不斷更新left和right的值,並由此確定mid。
最後退出循環,我們的left就是目標元素的指針了。
這裏只需要判斷右指針的情況,這樣以來我們就不用判斷左邊區域的情況了。
class Solution {
public:
int findMin(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while(left < right){
int mid = left + (right - left) / 2;
if(nums[mid] < nums[right])
right = mid;
else if(nums[mid] > nums[right])
left = mid + 1;
}
return nums[left];
}
};