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;
    }
};
posted @ 2020-04-30 20:25  又啦  阅读(163)  评论(0编辑  收藏  举报