这道题用到了二分
能用二分的题目不一定要有序,而是能有将区间一份为二的性质(这里的一分为二,不代表两个区间相等,仅仅是将一个区间分成了两个),只不过在区间里面二分求值刚好需要序列的单调性
思路:
这个题有两段有序的序列,而二分需要知道序列的区间,所以我们要求出两个序列的断点,这里我们可以用二分,之前我们说了二分须有能将区间一分为二的性质,就说明有一个性质一个区间满足,另一个区间不满足,这里我们由题意可知这是一个升序序列,且将较大的序列旋转到前面来,那么是不是前面一个区间都大于等于nums[0],后面一个区间都小于nums[0],ok,这样我们就能找到断点了。
我们模拟一下找出断点的步骤,一开求下标mid,若》=nums[0]则说明mid在上半区间里,而且答案必然在mid的右边或在mid上,这里我们把l=mid。
找到断点后判断 目标值在哪个区间里,同样是根据nums[0]判断,然后二分求下标。
步骤:
1.根据性质是前面一个区间都大于等于nums[0],后面一个区间都小于nums[0],二分求断点
2.判断target在哪个区间内部,改变区间范围
3.二分求target,
注意:
这里写成nums[r], 当数组只有一个元素时, 两个二分查找代码都没有走, 而l在上面被+1, 这时会越界, 而r是length-1还是0, 不会产生越界
class Solution {
public:
int search(vector<int>& nums, int target) {
if(nums.empty())return -1;
int l=0,r=nums.size()-1;
while(l<r){
int mid=l+r+1>>1;
if(nums[mid]>=nums[0])l=mid;
else r=mid-1;
}
if(target>=nums[0])l=0;
else l=r+1,r=nums.size()-1;
while(l<r){
int mid=l+r>>1;
if(nums[mid]>=target)r=mid;
else l=mid+1;
}
if(nums[r]==target)return l;
else return -1;
}
};