题意理解
对一个数组旋转一部分元素,求数组中的最小值。
问题分析
找特征,如果旋转元素个数为0,那么最小数就是数组的第一个数字;如果个数不为0,那么最小元素藏在中间。旋没旋转可以通过判断首元素和尾元素大小判断。对于最小元素藏在中间的情况,使用二分法,最小元素左边的元素都比首元素大,右边的元素都比首元素小。判断mid是不是最小,可以通过特征邻接元素比大小来判断。
补充20200509:以上思路如果出现首尾中间三值相等无法正确处理。转换思路如下:
经过旋转后的数组分为两段,左边一段递增,右边一段递增,左边一段比右边一段都大。最小值的位置在右边一段的最前面。
low的变化范围包括左边一段+最小值;high的变化范围包括右边一段。
取中以后,如何移动low,high位置呢?将mid值和high值比较,如果比mid值大,说明在左边一段,将low设置为mid后一位,不是mid,因为low的范围可以包含最小值;如果比mid值小,说明在右边一段,将high设置为mid位,不是mid-1,因为high的范围不能超过右边一段。这样直到low==high,这时候的落点一定是最小值。
其他
同类型题目:力扣
20211024:有点难
链接
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];
}