力扣【二分查找】:1095. 山脉数组中查找目标值
- 题目描述:
(这是一个 交互式问题 )
你可以将一个数组 arr 称为 山脉数组 当且仅当:
arr.length >= 3
存在一些 0 < i < arr.length - 1 的 i 使得:
arr[0] < arr[1] < ... < arr[i - 1] < arr[i]
arr[i] > arr[i + 1] > ... > arr[arr.length - 1]
给定一个山脉数组 mountainArr ,返回 最小 的 index 使得 mountainArr.get(index) == target。如果不存在这样的 index,返回 -1 。
你无法直接访问山脉数组。你只能使用 MountainArray 接口来访问数组:
MountainArray.get(k) 返回数组中下标为 k 的元素(从 0 开始)。
MountainArray.length() 返回数组的长度。
- 算法思路:
按照题目描述,目标值可能在峰值左侧或者峰值右侧,所以我们可以先找到峰值,然后在峰值左右分别二分查找,如果左侧找到就返回,否则才在右侧找,
这里找峰值的二分法可以直接用第852题的方法,
随后的二分查找为了减少代码重复可以将二分过程封装成函数并通过回调函数来区别处理单调递增和单调递减,
力扣题解里通过对数值取负和保留原样的方式分开对递增区间和递减区间的二分,
我的解法里是用封装a > b和a < b的方式来分别处理递增和递减区间,
同样使用了lambda表达式
- 代码:
时间复杂度:O(log (n))
int findInMountainArray(int target, MountainArray &mountainArr) {
int size = mountainArr.length();
int left = 0, right = size - 1;
int peak_idx = -1;
while (left < right) {
int mid = left + (right - left) / 2;
int forward = mountainArr.get(mid + 1);
int curr = mountainArr.get(mid);
if (curr < forward) {
left = mid + 1;
} else {
right = mid;
peak_idx = mid;
}
}
int first_try = findResult(target, mountainArr, [](int a, int b) -> int {return a < b;}, 0, peak_idx);
if (first_try != -1) {
return first_try;
}
return findResult(target, mountainArr, [](int a, int b) -> int {return a > b;}, peak_idx + 1, size - 1);
}
int findResult(int target, MountainArray &mountainArr, int compare(int,int), int left, int right) {
while (left < right) {
int mid = left + ((right - left) >> 1);
int curr = mountainArr.get(mid);
if (compare(curr, target) > 0) {
left = mid + 1;
} else {
right = mid;
}
}
if (mountainArr.get(left) == target) {
return left;
}
return -1;
}
浙公网安备 33010602011771号