算法竞赛入门-二分

二分

二分主要解决的是,满足某一条件的最值问题,二分能解决的问题的性质具有二端性,即最值界点的左侧都满足或都不满足该性质,相对的右侧都不满足或都满足该性质。特殊的需要判断如果有重复值出现时最早和最晚的判断,相等是是收缩上界还是增大下界,即有以下两种情况:
1.最早值( 若 相 等 收 缩 上 界 若相等收缩上界
2.最晚值( 若 相 等 则 增 大 下 界 若相等则增大下界
以在一个升序数组中查找一个数为例。
它每次考察数组当前部分的中间元素,如果中间元素刚好是要找的,就结束搜索过程;如果中间元素小于所查找的值,那么左侧的只会更小,不会有所查找的元素,只需到右侧查找;如果中间元素大于所查找的值同理,只需到左侧查找。
时间复杂度:O(logN)
空间复杂度:O(1)

题目

给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。
对于每个查询,返回一个元素 k 的最早出现的位置和最晚出现的位置(位置从 0 开始计数)。
如果数组中不存在该元素,则返回 -1 -1。
给定数组:1 2 2 2 3 4
寻找:2
输出: 2 ,4
最小值条件:a[左]<2 a[临界点]=2 a[右]>=2
最大值条件 :a[左]<=2 a[临界点]=2 a[右]>2
可以发现:最大值与最小值的条件是不同的,对应不同的条件二分有不同的模板。

最小值模板

int l=0,r=n-1;
while(l<r)
    {
      int mid=l+r>>1;
       if(num[mid]>=t)r=mid;
       else l=mid+1;
    }
    return l

最大值模板

int check(int t)
 int l=0,r=n-1;
         while(l<r)
         {
             int mid=l+r+1>>1;
             if(num[mid]<=t)l=mid;
             else r=mid-1;
         }
         return l;

区别

这两种模板需要注意的有两个点:
1.a[i]==t时是应该将上界先左还是下界向右
2.mid=(l+r)>>1 还是 (l+r+1)>>1
当r=mid-1时需要用后者,理由是当r=mid-1=l时而又满足num[mid]<=t时会死循环。

二分答案

解题的时候往往会考虑枚举答案然后检验枚举的值是否正确。若满足单调性,则满足使用二分法的条件。把这里的枚举换成二分,就变成了“二分答案”。此举仅仅为优化枚举,主要是判断某个值是否满足题目给定的性质。

三分

三分法可以用来查找凸函数的最大(小)值。
如果 lmid 和 rmid 在最大(小)值的同一侧:由于单调性,一定是二者中较大(小)的那个离最值近一些,较远的那个点对应的区间不可能包含最值,所以可以舍弃。
如果在两侧:由于最值在二者中间,我们舍弃两侧的一个区间后,也不会影响最值,所以可以舍弃。

在这里插入图片描述

int SanFen(int l,int r) //找凸点  
{  
    while(l < r-1)  
    {  
        int mid  = (l+r)/2;  
        int mmid = (mid+r)/2;  
        if( f(mid) > f(mmid) )  
            r = mmid;  
        else  
            l = mid;  
    }  
    return f(l) > f(r) ? l : r;  
}  
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值