题目描述
给你一个 山脉数组 mountainArr,请你返回能够使得 mountainArr.get(index) 等于 target 最小 的下标 index 值。
如果不存在这样的下标 index,就请返回 -1。
何为山脉数组?如果数组 A 是一个山脉数组的话,那它满足如下条件:
- 首先,A.length >= 3
- 其次,在 0 < i < A.length - 1 条件下,存在 i 使得:
- A[0] < A[1] < … A[i-1] < A[i]
- A[i] > A[i+1] > … > A[A.length - 1]
你将 不能直接访问该山脉数组,必须通过 MountainArray 接口来获取数据:
- MountainArray.get(k) - 会返回数组中索引为k 的元素(下标从 0 开始)
- MountainArray.length() - 会返回该数组的长度
题目分析
本博客参考题解
通过题目,和给出的数据,很明显这个目标值,可以在峰值的左右两边都出现,但由于是严格的排序关系,最多出现两次,需要给出目标值在山脉数组中下标的较小值。
如果目标值,在峰值左侧出现,无需对右侧进行处理;反之,需要对右侧进行处理。
说了这么多,重点很明显,如何从山脉数组中获取峰值 ?
相信大家都 AC了 力扣:852. 山脉数组的峰顶索引 ,如果没有 请先参考该篇博客
在获取到峰值的下标 pickIndex后,问题转变成在 [ 0 , pickIndex ] 升序区间 ,和 ( pickIndex , mountainArr.length() - 1 ] 降序区间 内二分查找目标值。
/**
* // This is MountainArray's API interface.
* // You should not implement it, or speculate about its implementation
* interface MountainArray {
* public int get(int index) {}
* public int length() {}
* }
*/
class Solution {
public int findInMountainArray(int target, MountainArray mountainArr) {
// 首先找到 峰值
int left = 0 , right = mountainArr.length() - 1;
// 二分查找万能模板
while(left + 1 < right){
int mid = left + (right - left) / 2;
int midValue = mountainArr.get(mid);
if(midValue > mountainArr.get(mid - 1)){ // 上坡
left = mid;
} else { // 下坡
right = mid;
}
}
int pickIndex = mountainArr.get(left) > mountainArr.get(right) ? left : right;
int target_index = binary(mountainArr , 0 , pickIndex , target , true);
// 如果在左侧区间有target 值, 一定是最小值 , 反之需要搜索 右区间
return target_index != -1 ? target_index : binary(mountainArr , pickIndex + 1 , mountainArr.length() - 1 , target , false);
}
// 由于 0 到 pickIndex 升序 ,
// 而 pickIndex + 1 到 moutainArr.length - 1 是降序 ,
// 二分查找方式不同 , 故这里用 isLeft 来区分
public int binary(MountainArray mountainArr , int left , int right , int target , boolean isLeft){
while(left <= right){
int mid = left + (right - left) / 2;
int midValue = mountainArr.get(mid);
if(midValue == target) return mid;
else if(midValue < target){
left = isLeft ? mid + 1 : left;
right = isLeft ? right : mid - 1;
} else {
right = isLeft ? mid - 1 : right;
left = isLeft ? left : mid + 1;
}
}
return -1;
}
}