问题
给你一个 山脉数组 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() - 会返回该数组的长度
注意: 对 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。
思路
所谓山脉数组,其实就是先升序再降序。其中最大的数据将数组分成两部分:一个升序序列,一个降序序列。分开后的两个序列可以使用二分法进行查找数据。现在的关键点是:怎么找到最大数据的下标。
最大数据有个特点,肯定比左边的数据大,也肯定比右边的数据大。再分析一下,如果二分法找到的mid,发现get(mid) < get(mid+1),那么肯定需要往右找;否则肯定需要往左找。剩下的就是边界问题了。一般的二分法,边界为low <= high。而此时需要判断mid+1,因此需要设定边界为low < high。
代码
/**
* // 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 indexOfMax = findIndexOfMax(mountainArr);
int left = find(target, mountainArr, 0, indexOfMax, true);
if (left >= 0) {
return left;
}
int right = find(target, mountainArr, indexOfMax, mountainArr.length()-1, false);
if (right >= 0) {
return right;
}
return -1;
}
private int find(int target, MountainArray mountainArr, int low, int high, boolean incr) {
while (low <= high) {
int mid = (low + high) / 2;
int cur = mountainArr.get(mid);
if (cur == target) {
return mid;
} else if (cur > target) {
if (incr) {
high = mid - 1;
} else {
low = mid + 1;
}
} else if (cur < target) {
if (incr) {
low = mid + 1;
} else {
high = mid - 1;
}
}
}
return -1;
}
private int findIndexOfMax(MountainArray mountainArr) {
int low = 0;
int high = mountainArr.length() - 1;
while (low < high) {
int mid = (low + high) / 2;
if (mountainArr.get(mid) < mountainArr.get(mid+1)) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
}
复杂度
时间复杂度:O(logn) 空间复杂度:O(1)
硬广告
欢迎关注公众号:double6