题目:
题解:
- 三次二分法寻找山脉数组中的目标值,
- 第一次二分:使用二分法的模板Ⅱ,寻找数组的山峰,将数组分为前半部分升序的数组和后半部分降序的数组
- 第二次二分:在前半部分升序数组中继续使用二分法的模板Ⅱ,寻找大于等于x的最小值
- 第三次二分:若在前半部分没有找到x,那么我们需要使用二分法的模板Ⅱ对后半部分降序数组中寻找x
代码如下:
class Solution {
public:
//思路:三次二分查找寻找目标值的最小下标
int findInMountainArray(int target, MountainArray &mountainArr) {
//注意使用闭区间,如果使用开区间,在[size-1,size)时mid取左中位数,mid+1会溢出,所以我们使用闭区间
int left=0,right=mountainArr.length()-1;
//第一次二分,寻找山脉的山峰
while(left<right){
//取左中位数,因为进入循环,数组一定至少有 2 个元素
//因此,左中位数一定有右边元素,数组下标不会发生越界
int mid=left+((right-left)>>1);
//mid所指的值大于等于mid+1,那么山峰在数组的左边,我们应该向左边逼近
if(mountainArr.get(mid)>=mountainArr.get(mid+1))right=mid;
//mid所指的值小于mid+1,那么山峰在数组的右边,我们应该向右边逼近
else left=mid+1;
}
//根据题意山峰一定存在,所以我们不用特判了
int peak=left;
//第二次二分,在前半部分升序数组中寻找target
left=0,right=peak;
while(left<right){
int mid=left+((right-left)>>1);
if(mountainArr.get(mid)>=target)right=mid;
else left=mid+1;
}
//在左边找到target,直接返回下标,否则在右半部分寻找
if(mountainArr.get(left)==target)return left;
//第三次二分,在后半部分降序数组中寻找target
left=peak+1,right=mountainArr.length()-1;
while(left<right){
int mid=left+((right-left)>>1);
//注意这里为<=,因为mid比x小,mid右边的元素肯定比x大,那么我们应该向左逼近
if(mountainArr.get(mid)<=target)right=mid;
else left=mid+1;
}
//在右边找到target后,直接返回下标,否则返回-1
if(mountainArr.get(left)==target)return left;
return -1;
}
};