題意理解
對一個數組旋轉一部分元素,求數組中的最小值。
問題分析
找特徵,如果旋轉元素個數爲0,那麼最小數就是數組的第一個數字;如果個數不爲0,那麼最小元素藏在中間。旋沒旋轉可以通過判斷首元素和尾元素大小判斷。對於最小元素藏在中間的情況,使用二分法,最小元素左邊的元素都比首元素大,右邊的元素都比首元素小。判斷mid是不是最小,可以通過特徵鄰接元素比大小來判斷。
補充20200509:以上思路如果出現首尾中間三值相等無法正確處理。轉換思路如下:
經過旋轉後的數組分爲兩段,左邊一段遞增,右邊一段遞增,左邊一段比右邊一段都大。最小值的位置在右邊一段的最前面。
low的變化範圍包括左邊一段+最小值;high的變化範圍包括右邊一段。
取中以後,如何移動low,high位置呢?將mid值和high值比較,如果比mid值大,說明在左邊一段,將low設置爲mid後一位,不是mid,因爲low的範圍可以包含最小值;如果比mid值小,說明在右邊一段,將high設置爲mid位,不是mid-1,因爲high的範圍不能超過右邊一段。這樣直到low==high,這時候的落點一定是最小值。
其他
同類型題目:https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/
鏈接
class Solution {
public:
int findMin(vector<int>& nums) {
int len=nums.size();
if(len==0) return -1;
if(len==1) return nums[0];
if(nums[0]<nums[len-1]) { //沒有旋轉元素的情況
return nums[0];
}
else {
int low=0, high=len-1;
while(low<high) { //二分查找
int mid=(low+high)/2;
if(nums[mid]>nums[mid+1]) return nums[mid+1]; //最小值判斷
if(nums[mid-1]>nums[mid]) return nums[mid]; //最小值判斷
if(nums[mid]>nums[0]) { //縮小範圍
low=mid+1;
}
else { //縮小範圍
high=mid-1;
}
}
}
return -1;
}
};
0509:
int minArray(vector<int>& numbers) {
int low = 0; //小端範圍在最小值及最小值左邊
int high = numbers.size() - 1; //大端範圍僅在最小值及最小值右邊
while (low < high) {
int mid = low + (high - low) / 2;
if (numbers[mid] < numbers[high]) {
high = mid;
}
else if (numbers[mid] > numbers[high]){
low = mid + 1;
}
else {
high --; //關鍵代碼
}
}
return numbers[low];
}