LeetCode 1095. 山脉数组中查找目标值
给你一个山脉数组mountainArr请你返回能够使得mountainArr.get(index)等于target 最小的下标index值。
如果不存在这样的下标index就请返回 -1。
链接: https://leetcode-cn.com/problems/find-in-mountain-array.
在写这道题时,我们首先需要得知什么是山脉数组(解释在leetcode上已经解释的十分清楚了)。
如果数组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]
再得知什么是山脉数组以后,我们就可以对这道题进行求解了。并且要注意的是题目要求我们求得的是最小的下标值。
这道题目主要考察的是对二分查找的理解,本题思路可以分为三个步骤:
- 首先找到数组中的最大的值
- 在数组左边—最大值之间寻找target
- 若未在左边找到值,则我们需要在最大值—右边寻找target
在了解解题思路以后,我们就可以完全套用二分查找的模板了。
//二分查找模板
//使用二分查找的前提是该数组是排过序的,即数组是有序的
public int binarySearch(int target, int[] arr, int left, int right){
while(left <= right){
int mid = left + ((right - left) >> 1); //这样写可以防止left + right 溢出
if(arr[mid] == target) return mid;
else if(arr[mid] < target) //如果中间值 < target, 我们需要在左边查找
left = mid - 1;
else //如果中间值 > target, 我们需要在右边查找
right = mid + 1;
}
//最后没有找到的话返回-1
return -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() {}
* }
*/
public int findInMountainArray(int target, MountainArray mountainArr) {
int size = mountainArr.length();
//首先找到制高点
int i = findMountainTop(mountainArr, 0, size - 1);
int res = -1;
//左边---制高点 找target
res = findMountainLeft(target, mountainArr, 0, i);
if(res != -1) return res;
//制高点---右边 找target
res = findMountainRight(target, mountainArr, i + 1, size - 1);
return res;
}
public int findMountainTop(MountainArray mountainArr, int left, int right){
while(left <= right){
int mid = left + ((right - left) >> 1);
if(mountainArr.get(mid) < mountainArr.get(mid + 1)){
left = mid + 1;
}else{
right = mid - 1;
}
//此处返回left是根据上面的判断条件,如果
//mountainArr.get(mid) > mountainArr.get(mid + 1),则左边的一定是最大值
return left;
}
public int findMountainLeft(int target, MountainArray mountainArr, int left, int right){
//这里写left <= right的原因是考虑到数组中只有一个元素的情况,当然也可以写left < right
//不过下面的判断条件需要仔细考虑一下边界条件
while(left <= right){
int mid = left + ((right - left) >> 1);
if(mountainArr.get(mid) == target) return mid;
else if(mountainArr.get(mid) < target){
left = mid + 1;
}else
right = mid - 1;
}
return -1;
}
public int findMountainRight(int target, MountainArray mountainArr, int left, int right){
while(left <= right){
int mid = left + ((right - left) >> 1);
if(mountainArr.get(mid) == target) return mid;
else if(mountainArr.get(mid) < target){
//这里需要注意的是山脉数组右半部分左边的值 > 右边的值
right = mid - 1;
}else
left = mid + 1;
}
return -1;
}