leetcode 162. 寻找峰值(二分)

在这里插入图片描述
转自https://blog.csdn.net/qq_41231926/article/details/86369916
在这里插入图片描述

这个博客说的很清楚。

首先第一次拿到题的时候是给了这样的条件,给一个序列a,序列a[0]<a[1] && a[n-1]<a[n-2]

序列中间是无序的,求某个位置i,使得a[i]>a[i+1]&&a[i]>a[i-1]

要用log级别的方法。

首先对于这样一个问题,一般想着肯定是暴力跑一遍,得到第一个符合条件的i就输出即可。

然后这里说要log级别的方法,那么想到的只有二分或者三分,而序列又是无序的,就想不出怎么分了。

首先可以注意到的是该题要找峰值,而且是连续三个数中的峰值。如何二分是个问题。注意到左右两端已经给出了趋势,即是左边上升,右边下降。

而我们可以采取这样的策略,二分取得mid后,若其于左边的值形成下降趋势,那么于最左端相连之后,一定会形成一个峰值,右端也是一样的,所以我们尽量选取mid<mid+1或mid<mid-1的方向继续进行二分。

不用在意mid与其相邻值对于最左最右端的大小,因为无论大小,二者相连后都会形成峰值,因为这两个值旁边都有一个小于自己的数。

即使我们不知道该峰值是谁,但是可以明确的是,因为两端有这样的趋势,那么不断缩小距离,就离峰值越来越近

代码如下:

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int l=0,r=nums.size()-1;
        if(r<=2)
        {
            if(r==0)return 0;
            else if(r==1)return nums[0]>nums[1]?0:1;
            else
            {
                int ans=0;
                if(nums[0]>nums[1])ans=0;
                else ans=1;
                if(nums[ans]>nums[2])return ans;
                else return 2;
            }
        }
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(mid==0)return nums[0]>nums[1]?0:1;
            if(nums[mid]>nums[mid+1]&&nums[mid]>nums[mid-1]) return mid;
            else if(nums[mid]>nums[mid+1])r=mid-1;
            else l=mid+1;
        }
        return l;
    }
};
posted @ 2019-04-25 22:44  KuroNekonano  阅读(260)  评论(0编辑  收藏  举报