LeetCode 1095 山脉数组中查找目标值(二分法)

这道题大意是给出一个山脉数组,山脉数组的特点是长度不小于3,有一个数为山顶,这个数左边是递增数组,右边是递减数组,求出数组第一个出现值为target的数的下标,如果没有返回-1。数组最大长度能到10000,不能去遍历这个数组,因为最多只能访问100次数组,那么首先我想到的方法就是二分。整个数组又不是按序排列的,不能直接二分,应该先想办法去找到山顶,之后就好做了。首先把数组大概五等分,求出第二三四个点的数的值,这三个点可能出现有三种情况,第一个数>=第二个数且第二个数>=第三个数,第一个数<=第二个数且第二个数>=第三个数,第一个数<=第二个数且第二个数<=第三个数,这三种情况分别可以获取新的山顶所在的范围,详情见代码,注意这里的边界要处理好,否则可能陷入一直递归的情况。如果当前范围小于等于三,那么就可以确定山顶在范围中,依次验证每个点直到确定出山顶即可。确定完山顶之后其余的就简单了,在山顶左右两边分别二分去求是否出现target,如果出现了取较小的坐标值,否则返回-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 len;
    int num[10005],vis[10005];
    int get_index(MountainArray &mountainArr,int left,int right)
    {
        if(right-left<=2)
        {
            for(int i=left;i<=right;i++)
            {
                if(i<=0||i>=len-1) continue;
                int save[3];
                for(int j=-1;j<=1;j++)
                {
                    if(!vis[i+j])
                    {
                        vis[i+j]=1;
                        num[i+j]=mountainArr.get(i+j);
                    }
                    save[j+1]=num[i+j];
                }
                if(save[1]>save[0]&&save[1]>save[2])
                    return i;
            }
            return -1;
        }
        int mid=(right+left)/2;
        int pos1=(mid+left)/2,pos2=mid,pos3=(mid+right)/2;
        int val1,val2,val3;
//        cout<<pos1<<' '<<pos2<<' '<<pos3<<endl;
        if(!vis[pos1])
        {
            num[pos1]=mountainArr.get(pos1);
            vis[pos1]=1;
        }
        if(!vis[pos2])
        {
            num[pos2]=mountainArr.get(pos2);
            vis[pos2]=1;
        }
        if(!vis[pos3])
        {
            num[pos3]=mountainArr.get(pos3);
            vis[pos3]=1;
        }
        if(num[pos1]>=num[pos2]&&num[pos2]>=num[pos3])
        {
//            cout<<1<<endl;
            return get_index(mountainArr,left,pos3-1);
        }  
        if(num[pos1]<=num[pos2]&&num[pos2]>=num[pos3])
        {
//            cout<<2<<endl;
            return get_index(mountainArr,pos1+1,pos3-1);
        }
        if(num[pos1]<=num[pos2]&&num[pos2]<=num[pos3])
        {
//            cout<<3<<endl;
            return get_index(mountainArr,pos1+1,right);
        }
        return -1;
    }
    int findInMountainArray(int target, MountainArray &mountainArr) {
        int ans=0;
        len=mountainArr.length();
        int i=get_index(mountainArr,0,len-1);
        int pos=-1;
        int left=0,right=i,mid;
        while(left<=right)
        {
            mid=(left+right)/2;
            if(!vis[mid])
                num[mid]=mountainArr.get(mid);
            if(num[mid]<target)
                left=mid+1;
            else if(num[mid]>target)
                right=mid-1;
            else
            {
                pos=mid;break;
            }
        }
        if(pos==-1)
        {
            left=i;
            right=len-1;
            while(left<=right)
            {
                mid=(left+right)/2;
                if(!vis[mid])
                    num[mid]=mountainArr.get(mid);
                if(num[mid]>target)
                    left=mid+1;
                else if(num[mid]<target)
                    right=mid-1;
                else
                {
                    pos=mid;break;
                }
            }
        }
        return pos;
    }
};
posted @ 2020-04-29 21:14  South1999  阅读(167)  评论(0编辑  收藏  举报