1095. 山脉数组中查找目标值 (多次二分/三分查找)
题目链接:https://leetcode-cn.com/problems/find-in-mountain-array/
题意 : 存在一个“山峰”数组,但是不能直接访问,只能通过get()函数来得到其相应坐标的值,要求在这个数组中找一个target,如果存在,返回索引,反之返回-1。
解题思路 : 由于get()的次数受到限制,因此不能使用线性复杂度的方法去寻找。可优先考虑二分搜索。在自己做的过程中,设计出了一个类似于三分搜索的算法,来寻找到山峰位置,随后的问题就规约为两段普通的二分查找了。事实上,寻找山峰位置也可以用一次二分搜索来实现,每一次只要计算get(mid)和get(mid+1)即可。
下面展示我的代码,虽然二分的思路更自然效率更高,但在遇到别的问题时,这种三分的思想也可作为一种借鉴
/**
* // This is the MountainArray's API interface.
* // You should not implement it, or speculate about its implementation
* class MountainArray {
* public:
* int get(int index);
* int length();
* };
*/
class Solution {
public:
int findInMountainArray(int target, MountainArray &mountainArr) {
int n = mountainArr.length();
int topPos = findMidPos(0,n-1,mountainArr);
int result = BinarySearch(0,topPos,mountainArr,target);
if(result == -1) return BinarySearch1(topPos,n-1,mountainArr,target);
else return result;
}
//直接找到两个相邻的元素就可用二分找到topPos,效率更高
//三分容易出错,不熟悉
int findMidPos(int left, int right, MountainArray &mountainArr){
if(left == right) return left;
int pos1 = (2*left+right)/3;
int pos2 = (left+2*right)/3;
int valPos1 = mountainArr.get(pos1);
int valPos2 = mountainArr.get(pos2);
if(pos1 == pos2) return valPos1 > valPos2? left:right; //三分割法
if(valPos1 == valPos2) return findMidPos(pos1+1,pos2-1,mountainArr);
else if(valPos1 > valPos2) return findMidPos(left,pos2-1,mountainArr);
else return findMidPos(pos1+1,right,mountainArr);
}
int BinarySearch(int left, int right, MountainArray &mountainArr, int target){
while(left <= right){
int mid = (left+right)/2;
int valMid = mountainArr.get(mid);
if(valMid == target) return mid;
else if (valMid > target) right = mid - 1;
else left = mid + 1;
}
return -1;
}
int BinarySearch1(int left, int right, MountainArray &mountainArr, int target){
while(left <= right){
int mid = (left+right)/2;
int valMid = mountainArr.get(mid);
if(valMid == target) return mid;
else if (valMid < target) right = mid - 1;
else left = mid + 1;
}
return -1;
}
};