C++实现二分法的一些细节(常用场景)

 更新时间:2021年07月08日 08:43:10   作者:ZhiboZhao  
二分法算法思想首先确定有根区间,将区间二等分,通过判断f(x)的符号,逐步将有根区间缩小,直至有根区间足够小,便可求出满足精度要求的近似值

二分法是在一个排好序的序列(数组,链表等)中,不断收缩区间来进行目标值查找的一种算法,下面我们就来探究二分法使用的一些细节,以及常用的场景:

寻找一个数;寻找左侧边界;寻找右侧边界。

一、二分法的通用框架

int binarySearch(vector<int>& nums, int target){
    int left=0, right=nums.size();
    while(left < right)
    {
        int mid=(left+right)/2;
        if(nums[mid] == target){
            // 条件一:中间的值与目标值相同
        }
        else if(nums[mid] > target){
            // 条件二:中间的值大于目标值
        }
        else if(nums[mid] < target){
            // 条件三:中间的值小于目标值
        }
    }
    return -1;	
}

首先,我们先来分析一下右边界 right 的初始值:

  • right=nums.size() 时,初始化的区间就变成了 \([0, right-1]\),即 \([0,right)\);
  • right=nums.size()-1 时,初始化的区间就变成了 \([0, right]\)。

在第一种情况下,当 nums[mid] > target 时,需要将区间向左收缩,即 right=mid。这个做法的逻辑是:既然 mid 位置处大于 target,而查找区间又是 “左闭右开”,因此当 right=mid 时,新的查找区间变成了 \([0, mid)\),这样才不会漏掉值。同理,当 nums[mid] < target 时,需要将区间向右收缩,即 left = mid+1,因为在 "左闭右开" 的区间下,新的查找区间变成 \([mid+1, right)\) 才不会漏掉值。当目标值不在序列中时,需要将 while 的条件写成 while(left < right) 而不是写成 while(left<=right),这样会引起数组越界。

第二种情况的分析类似,这里只给出结论:

  • nums[mid] > target 时,需要将区间向左收缩,即 right=mid-1
  • nums[mid] < target 时,需要将区间向右收缩,即 left = mid+1
  • 当目标值不在序列中时,需要将 while 的条件写成 while(left<=right)

二、二分法查找目标值

在序列中查找一个数,如果存在则返回数的索引,如果不存在则返回 -1 。为了方便分析,我们就只用第一种情况进行说明:

int binarySearch(vector<int>& nums, int target){
    int left=0, right=nums.size();
    while(left < right)
    {
        int mid=(left+right)/2;
        if(nums[mid] == target){
           return mid;	// 查询到目标值,直接返回目标值的位置
        }
        else if(nums[mid] > target){
            right = mid; // 中间的值大于目标值,向左收缩区间
        }
        else if(nums[mid] < target){
            left = mid+1;// 中间的值小于目标值,向右收缩区间
        }
    }
    return -1;	// 当没有找到,直接返回-1
}

三、二分法查找目标值的左右边界

上述代码只能从序列中查找一个目标值并返回位置,当一个序列中目标值不止一个时,我们需要找到目标值最左边的位置和最右边的位置,这时候二分法需要进行改写:

// 查找目标值的左边界
int binarySearch(vector<int>& nums, int target){
    int left=0, right=nums.size();
    while(left < right)
    {
        int mid=(left+right)/2;
        if(nums[mid] == target){
          right = mid;	// 查询到目标值不进行返回,而是收缩区间继续查找
        }
        else if(nums[mid] > target){
            right = mid; // 中间的值大于目标值,向左收缩区间
        }
        else if(nums[mid] < target){
            left = mid+1;// 中间的值小于目标值,向右收缩区间
        }
    }
    return left;	
}

根据上述代码,可以发现如果查找目标值的左边界,在满足 nums[mid] == target 时,需要缩小搜索区间的上界 right,在区间 \([left, mid]\) 中继续搜索,直到搜索完毕 left==right。此时 left=right=左边界

查找右边界的做法与左边界类似:

// 查找目标值的左边界
int binarySearch(vector<int>& nums, int target){
    int left=0, right=nums.size();
    while(left < right)
    {
        int mid=(left+right)/2;
        if(nums[mid] == target){
          left = mid+1;	// 查询到目标值不进行返回,而是收缩区间继续查找
        }
        else if(nums[mid] > target){
            right = mid; // 中间的值大于目标值,向左收缩区间
        }
        else if(nums[mid] < target){
            left = mid+1;// 中间的值小于目标值,向右收缩区间
        }
    }
    return left-1;	
}

注意这里的判断条件改成了当 nums[mid] == target 时,left = mid+1。因为搜索的区间为 "左闭右开",所以在寻找左边界时可令 right=mid ,在寻找右边界时必须另 left=mid+1,不然程序会一直停在循环里面而无法跳出循环。

到此这篇关于C++实现二分法详解的文章就介绍到这了,更多相关C++实现二分法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++程序设计-五子棋

    C++程序设计-五子棋

    本文将以简单的存储结构及简单的运算,条件语句,分支语句,循环语句结合,带来一个双人对战版五子棋,这是一个简单的模型,实现了五子棋最最基本的功能。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • 详解设计模式中的中介者模式在C++编程中的运用

    详解设计模式中的中介者模式在C++编程中的运用

    这篇文章主要介绍了设计模式中的中介者模式在C++编程中的运用,中介者模式将对象间的通信封装到一个类中,将多对多的通信转化为一对多的通信,降低了系统的复杂性,需要的朋友可以参考下
    2016-03-03
  • 哈夫曼算法构造代码

    哈夫曼算法构造代码

    这篇文章主要介绍了哈夫曼算法构造代码,有需要的朋友可以参考一下
    2013-12-12
  • C++或Go求矩阵里的岛屿的数量详解

    C++或Go求矩阵里的岛屿的数量详解

    这篇文章主要介绍了C++和go实现LeetCode(200.岛屿的数量),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • C++强制类型转换的四种方式

    C++强制类型转换的四种方式

    本文主要介绍了C++强制类型转换的四种方式,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • 详解Matlab中自带的Java操作合集

    详解Matlab中自带的Java操作合集

    其实Matlab中也有一些自带的Java操作,例如:获取鼠标在全屏位置、获取当前剪切板内容、获取鼠标处像素颜色等,本文总结了七个这样的操作,感兴趣的可以了解一下
    2022-03-03
  • Opencv下载和导入Visual studio2022的实现步骤

    Opencv下载和导入Visual studio2022的实现步骤

    本文主要介绍了Opencv下载和导入Visual studio2022的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • c语言合并两个已排序数组的示例(c语言数组排序)

    c语言合并两个已排序数组的示例(c语言数组排序)

    如何将两个已排序数组合并成一个排序数组,下面我们给出使用c语言合并两个已排序数组的示例,需要的朋友可以参考下
    2014-03-03
  • C/C++ 获取Windows系统的位数32位或64位的实现代码

    C/C++ 获取Windows系统的位数32位或64位的实现代码

    这篇文章主要介绍了C/C++ 获取Windows系统的位数32位或64位的实现代码的相关资料,希望通过本文能帮助到大家,让大家实现这样的功能,需要的朋友可以参考下
    2017-10-10
  • 使用devenv在命令行中编译项目的方法

    使用devenv在命令行中编译项目的方法

    下面小编就为大家分享一篇使用devenv在命令行中编译项目的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01

最新评论