C++实现二分法详解
二分法是在一个排好序的序列(数组,链表等)中,不断收缩区间来进行目标值查找的一种算法,下面我们就来探究二分法使用的一些细节,以及常用的场景:
- 寻找一个数;
- 寻找左侧边界;
- 寻找右侧边界。
一、二分法的通用框架
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++实现二分法详解的更多相关文章
- Python中的高级数据结构详解
这篇文章主要介绍了Python中的高级数据结构详解,本文讲解了Collection.Array.Heapq.Bisect.Weakref.Copy以及Pprint这些数据结构的用法,需要的朋友可以参考 ...
- javascript 中合并排序算法 详解
javascript 中合并排序算法 详解 我会通过程序的执行过程来给大家合并排序是如何排序的... 合并排序代码如下: <script type="text/javascript& ...
- 深入MySQL用户自定义变量:使用详解及其使用场景案例
一.前言 在前段工作中,曾几次收到超级话题积分漏记的用户反馈.通过源码的阅读分析后,发现问题出在高并发分布式场景下的计数器上.计数器的值会影响用户当前行为所获得积分的大小.比如,当用户在某超级话题下连 ...
- SQL注入漏洞技术的详解
SQL注入漏洞详解 目录 SQL注入的分类 判断是否存在SQL注入 一:Boolean盲注 二:union 注入 三:文件读写 四:报错注入 floor报错注入 ExtractValue报错注入 Up ...
- 二分算法题目训练(四)——Robin Hood详解
codeforces672D——Robin Hood详解 Robin Hood 问题描述(google翻译) 我们都知道罗宾汉令人印象深刻的故事.罗宾汉利用他的射箭技巧和他的智慧从富人那里偷钱,然后把 ...
- 线段树详解 (原理,实现与应用)(转载自:http://blog.csdn.net/zearot/article/details/48299459)
原文地址:http://blog.csdn.net/zearot/article/details/48299459(如有侵权,请联系博主,立即删除.) 线段树详解 By 岩之痕 目录: 一:综述 ...
- 丰富图文详解B-树原理,从此面试再也不慌
本文始发于个人公众号:TechFlow,原创不易,求个关注 本篇原计划在上周五发布,由于太过硬核所以才拖到了这周五.我相信大家应该能从标题当中体会到这个硬核. 周五的专题是大数据和分布式,我最初的打算 ...
- RocketMQ源码详解 | Broker篇 · 其三:CommitLog、索引、消费队列
概述 上一章中,已经介绍了 Broker 的文件系统的各个层次与部分细节,本章将继续了解在逻辑存储层的三个文件 CommitLog.IndexFile.ConsumerQueue 的一些细节.文章最后 ...
- Linq之旅:Linq入门详解(Linq to Objects)
示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...
随机推荐
- 【转载】geany linux python编译器 开源
http://www.dekiru.cn/?p=1491 Geany 不好用,建议用一些好用的编辑器或ide Subliem Text 或 VS code Pycharm等. 设置运行环境 菜单栏–生 ...
- -bash: ll: 未找到命令
第一步将alias ll='ls -l'添加到/etc/profile # head /etc/profile# /etc/profilealias ll='ls -l'# System wide e ...
- WPS-插入-公式-菜单 怎样在EXCEL中使用PRODUCT函数
怎样在EXCEL中使用PRODUCT函数 ################ WPS2018 -插入-公式-[专门有公式菜单] 插入函数 ################## ...
- MySQL给某个用户给某个库表设置权限
-- 用root(最高权限的用户)进行以下操作-- 创建数据库:emc_power CREATE DATABASE emc_power DEFAULT CHARACTER SET utf8 COLLA ...
- mysql有关配置
mysql有关配置 mysql安装 mysql安装方式有三种 源代码:编译安装 二进制格式的程序包:展开至特定路径,并经过简单配置后即可使用 程序包管理器管理的程序包: rpm:有两种 OS Vend ...
- 上,打开SSH服务的配置文件:/etc/ssh/sshd_config 加上如下两行: ClientAliveInterval 120 ClientAliveCountMax 720 第一行,表示每隔120秒向客户端
SSH的默认过一段时间会超时,有时候正在执行着脚本,出去一会回来就断开了,输出信息都看不到了... 禁止SSH自动超时最简单的办法就是,每隔一段时间在客户端和服务器之间发送一个"空包&quo ...
- 在Linux服务器,搭建K8s服务【脚本篇】
前言 好久没有写博客了,本文主要是对网上文章的总结篇,主要是将安装和运行代码做了一次真机实验,亲测可用.文章内包含的脚本和代码,多来自于网络,也有我自己的调整和配置,文章末尾对参考的文献做了列举,方便 ...
- GO学习-(14) Go语言基础之接口
Go语言基础之接口 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节. 接口 接口类型 在Go语言中接口(interface)是一种类型,一种抽象的类 ...
- Jmeter- 笔记9 - CLI(无图形界面)
使用CLI模式,减少资源占用 用GUI调试好脚本 在jmeter的bin文件夹运行cmd,然后输入命令:jmeter -n -t [jmx file] -l [results file] -e -o ...
- 3层-CNN卷积神经网络预测MNIST数字
3层-CNN卷积神经网络预测MNIST数字 本文创建一个简单的三层卷积网络来预测 MNIST 数字.这个深层网络由两个带有 ReLU 和 maxpool 的卷积层以及两个全连接层组成. MNIST 由 ...