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;
}
};