二分查找核心思路--单调性--极值

在最初的二分查找中,我们将一组数据按大小排序,然后根据arr[mid]与要查找的k的大小比较,从而每次去掉一半的数字,使时间复杂度简化为O(logN)。

排序本质上是让数据的单调性统一,变为单增或单减,而不是混合的。

下面我们看一道好题:

寻找峰值_牛客题霸_牛客网

 

找出两个山峰,山峰是一个比两边都大的数字,也就是这组数据的极大值(极值点是坐标)

   //处理两个边界
    if(numsLen==1||nums[0]>nums[1])
    {
        return 0;
    }
    if(nums[numsLen-1]>nums[numsLen-2])
    {
        return numsLen-1;
    }

数据的首尾比较好判断,且题目中规定越界的部分为负无穷,我们可以先将这两部分判断好。

确保首尾均不是极值后,我们可以得到下图。

两边向下的箭头:代表靠近首尾边界时,均为单调递减 。即left<left+1对应的值,right<right-1对应的值。

然后我们对中间的值与其附近的值进行比较。这里我假设arr[mid]<arr[mid+1],则中间向右位置是单调递增的,而右边部分可以近似理解为连续的函数(实际上是数列),一开始单增,导数>0,最后单减,导数<0,则其中必定有导数=0的极值点,因此我们就可以确定mid向右部分一定存在峰值

然而,对于左半边的部分,起始和终止均为单增,单调性一致,无法确定是否存在峰值。

int findPeakElement(int* nums, int numsLen )
{
    //处理两个边界
    if(numsLen==1||nums[0]>nums[1])
    {
        return 0;
    }
    if(nums[numsLen-1]>nums[numsLen-2])
    {
        return numsLen-1;
    }
    int i=0;
    int left=0;
    int right=numsLen-1;
    int mid=0;
    while(left<right)
    {
        mid=(right-left)/2+left;
        if(nums[mid]<nums[mid+1])
        {
            left=mid+1;
        }
        else
        {
            right=mid;
        }
      
    }
    mid=(right-left)/2+left;
    return mid;
}

left=mid+1,因为mid不可能是峰值。right=mid,因为此时mid可能是峰值。

二分查找的时间复杂度为O(logN),是一种高效的查找方式,在做相关题目,要注意找到单调性的规律,满足什么条件时单调性改变,产生极值,是解题的关键,找到单调性的规律后,就可以一次排查掉一半数据了,还有就是注意left<right开闭区间等情况即可。

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值