问题描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个升序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
数组可能包含重复项。
注意:数组内所含元素非负,若数组大小为0,请返回-1。
样例
- 输入:nums=[2,2,2,0,1]
- 输出:0
巧妙地使用了二分法,附上大佬的题解过程,乍一看,好像不好理解,仔细一看,发现很巧妙。首先是去掉最后一段不满足单调递增的数组部分,其余部分都是满足二分条件,最特殊的例子比如[2,0,1,2,2]除去最后那段重复的部分,[2,0,1]这部分就满足二分条件,nums[i]>=nums[0],以0为分界点,有半段不满足,这样使用二分将 r 所在位置找出来即可。特殊情况输入的例子本来就是递增数列,那么只需要将nums[0]输出即可。旋转数组之后最小值在后半段。需要看mid在数组的左半段还是右半段。
class Solution {
public:
int findMin(vector<int>& nums) {
int l=0,n=nums.size()-1;
if(n<0) return -1;
while(n>0&&nums[n]==nums[0]) n--;
if(nums[n]>nums[0]) return nums[0];
int r=n;
while(l<r)
{
int mid=(r+l)/2;
if(nums[mid]<nums[0]) r=mid; //mid在后半段,有可能是等于mid
else l=mid+1;//说明mid在左半段
}
return nums[r];
}
};
中间部分变换成下面的代码需要注意加上等号,因为这样一开始判断的是mid在左边段,左半段有可能是样例[3,3,1,2]所显示的那样,如果去掉等号返回的结果是3,而不是1。
while(l<r)
{
int mid=(l+r)>>1;
if(rotateArray[0]<=rotateArray[mid]) l=mid+1;
else r=mid;
}
类似的题目【搜索旋转排序数组 II】有重复值和无重复值需要注意。这个题目是寻找目标值,目标值所在的位置可以是前半段也可以是后半段,因此需要分两种情况讨论。