# 1095. 山脉数组中查找目标值
给你一个山脉数组mountainArr
,请你返回能够使得 mountainArr.get(index)
等于 target
最小的下标 index
值。
如果不存在这样的下标 index
,就请返回 -1
。
什么是山脉数组呢?
就是先升序再降序的数组,比如[1,2,3,4,5,3,1]。
注意:
-
你将不能直接访问该山脉数组,必须通过 MountainArray 接口来获取数据:
1.1
MountainArray.get(k)
- 会返回数组中索引为k 的元素(下标从 0 开始)1.2
MountainArray.length()
- 会返回该数组的长度 -
对
MountainArray.get
发起超过100次
调用的提交将被视为错误答案。此外,任何试图规避判题系统的解决方案都将会导致比赛资格被取消。
示例 1:
输入:array = [1,2,3,4,5,3,1], target = 3
输出:2
解释:3 在数组中出现了两次,下标分别为 2 和 5,我们返回最小的下标2。
示例 2:
输入:array = [0,1,2,4,2,1], target = 3
输出:-1
解释:3 在数组中没有出现,返回 -1。
提示:
3 <= mountain_arr.length() <= 10000
0 <= target <= 10^9
0 <= mountain_arr.get(index) <= 10^9
思路
- 题目要求不能调用超过100次,数组长度最大10000,所以不能直接遍历。
- 显然题目应该用二分法。
- 山顶元素把数组分为两部分,升序部分和降序部分。
- 找到山顶元素,然后分别对两侧进行二分查找。
- 山顶元素也是通过二分法查找。
- 如果左中位数小于左中位数右侧元素,说明在山左侧,继续往右查找。
- 如果左中位数大于左中位数右侧元素,说明在山右侧,继续往左查找。
代码
/**
* // 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 n = mountainArr.length();
//找到山顶
int mountainTop = findMountainTop(mountainArr,0,n-1);
//在前半部分升序数组中查找target
int index = findIncreValue(mountainArr,0,mountainTop,target);
if(index != -1) return index;
//前半部分没找到,搜索后半部分降序数组
index = findInversedValue(mountainArr,mountainTop+1,n-1,target);
return index;
}
public int findMountainTop(MountainArray mountainArr,int left, int right){
while(left<right){
//取此部分区间的左中位数
int mid = left + (right-left)/2;
//如果左中位数小于它的右侧元素,那它肯定不是山顶
if(mountainArr.get(mid)<mountainArr.get(mid+1)) left = mid+1;
else right = mid;
}
//退出循环时,左侧等于右侧,就相遇在山顶。
//return left;
return right;
}
//寻找升序数组中的目标。
public int findIncreValue(MountainArray mountainArr,int left, int right, int target){
while(left<right){
//取左中位数
int mid = left + (right-left)/2;
if(mountainArr.get(mid)<target) left = mid + 1;
else right = mid;
}
//直到l和r相遇,判断此时的值是不是target。
if(mountainArr.get(left) == target) return left;
else return -1;
}
//寻找降序数组中的目标
public int findInversedValue(MountainArray mountainArr,int left, int right, int target){
while(left<right){
int mid = left + (right-left)/2;
if(mountainArr.get(mid)>target) left = mid+1;
else right = mid;
}
if(mountainArr.get(left) == target) return left;
else return -1;
}
}