zoukankan      html  css  js  c++  java
  • 对于二分的理解

    看了曦行夜落-浅谈二分的边界问题后深有感触,特此写下此篇博客以作梳理。

    简介

       二分是一种求取极值的算法,通常是已知所求答案的范围,然后根据一系列约束条件对其进行控制使得到的答案最优。二分答案需要满足单调性,举个例子来看,我们要完求完成任务的最小代价(范围为1到100),我们考虑中间值50:

          如果以50的代价可以完成任务,那么,我们以51~100的代价显然也可以完成任务。

          如果以50的代价不能完成任务,那么,我们以0~50的代价就都不能完成任务。

      正是因为这种单调性,才使得二分可以在log2n的时间内完成查找工作。

    进行原理

      我们接着考虑上面的例子,我们可以发现:

          如果以50的代价可以完成任务,那么,我们以51~100的代价显然也可以完成任务。则,我们需要在0~50中去寻找更优的满足条件的解。

          如果以50的代价不能完成任务,那么,我们以0~50的代价就都不能完成任务。则,我们只能通过去牺牲数据,在51~100中去需找满足条件的解。

      这就是二分的进行机制,由此,我们可以发现,二分中真正重要的地方是中间条件的取值。

    对于二分中间值的讨论

      二分的中间值是二分过程中最容易出锅的地方, 对于是应该取mid + 1还是mid - 1又或是mid常常让人混乱,这里我们对其进行一定的梳理。

      二分中的主要思想有以下三种:

      1. l 和 r 所代表的”成本值”均可行(即当前讨论的区间为[ l, r]),且存在一个最优解ans。
      2. l 和 r 所代表的“成本值”均可行,最后答案是 l 和 r。
      3. l 和 r 所代表的“成本值”只有 l 可行而 r 不可行(即当前讨论的区间是[l, r ) ),最终的答案是 l。

      我们对前两种算法进行模板归纳

        思想1:储存答案

    for (;l<=r;)
    {
        int mid=(l+r)/2;
        if (check(mid))
        {
            ans=mid;
            r=mid-1;
        }
        else l=mid+1;
    }
    printf("%d",ans);

        结束条件是l > r 时停止循环,此时答案记录为ans。(依旧以上面举到的例子求大于条件的最小值)

        对于每次循环中的mid,都把当前的区间分为了三部分[l , mid - 1] , mid, [ mid + 1, r],这三部分中,我们根据mid处的值将问题分为两类。

      1. 当mid满足条件的时候,我们就把mid当作是的当前的最优解,然后去考虑[l, mid - 1]中有没有可以刷新当前最优解的更优解。
      2. 当mid不满足条件的时候,我们就考虑[mid + 1, r]中有没有可以满足条件的解。

        求大于的最小值则正好相反。

        思想2:不储存答案

    while (l<r)
    {
        int mid=(l+r)/2;
        if (check(mid)) r=mid
        else l=mid+1;
    }
    printf("%d",l); 

        结束条件是 (l == r),此时l 和 r 相同且都是最优解。(依旧以上面的例子求大于条件的最小值)

        对于每次循环中的mid,都把当前的区间分为了两部分[l, mid], [mid + 1, r],这两部分中我们根据mid的值将问题分为两类。

      1. 当mid满足条件的时候,我们把mid看作是一个可行解,根据二分的单调性我们可以知道[mid + 1, r]一定都满足条件且没有mid更优,所以我们可以得到更优的解一定是存在于[l, mid]中的。为什么要包括mid呢?我们可以这样来看,我们假设当mid就是满足条件的最优解而且这个区间中数的个数不只一个,如果我们只考虑[l, mid - 1]的话,就会因为漏解而使得最终答案错误。
      2. 当mid不满足条件的时候,根据单调性[l, mid]一定都不能满足条件,所以我们只需要在[mid + 1, r]中寻找满足条件的解即可。

        反过来,如果我们求的是小于条件的最大值时,对于每次循环中的mid, 都把当前区间分为了两部分[l, mid - 1],[mid, r],两部分。

    二分查找

      二分查找就是最经典的二分答案,我们对于一个有序序列,记录查找值为key的数, 而对于一个为key的数,我们既可以把他看作是满足大于条件的最小值,也可以看作是满足小于条件的最大值。

  • 相关阅读:
    33、VCF格式
    10、Perl5中19个最重要的文件系统工具
    9、perldoc文档阅读器
    32、Differential Gene Expression using RNA-Seq (Workflow)
    31、NGS 常用分析软件
    16、SGE作业调度系统的简介
    8、非root权限下安装perl以及perl模块
    31、SAM文件中flag含义解释工具--转载
    30、 bowtie和bowtie2使用条件区别及用法
    C#中委托。
  • 原文地址:https://www.cnblogs.com/2020pengxiyue/p/9372533.html
Copyright © 2011-2022 走看看