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,语言集 ...
随机推荐
- Ansible_静态和动态清单文件管理
一.利用主机模式选择主机 1.应用静态清单主机 1️⃣:主机模式用于指定要作为play或临时命令的目标的主机:在最简单的形式中,清单中受管主机或主机组的名称就是指定该主机或主机组的主机模式 简单演示实 ...
- JavaScript 实现简易版贪吃蛇(Day_13)
时光永远在变迁,你始终要丢下过去. 使用语言 JavaScript 概述 运用JavaScript 实现简易版<贪吃蛇>. Html 页面 1 <!DOCTYPE htm ...
- 90%的人都不知道的Node.js 依赖关系管理(下)
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文参考:https://dzone.com/articles/node-dependency-manage ...
- GO学习-(11) Go语言基础之map
Go语言基础之map Go语言中提供的映射关系容器为map,其内部使用散列表(hash)实现. map map是一种无序的基于key-value的数据结构,Go语言中的map是引用类型,必须初始化才能 ...
- Rabbitmqpool
import pika import threading import random import uuid import json # 框架模块 from django.conf import se ...
- jquery 改变标签样式
jQuery改变标签的样式一般有3种 预置好class,然后通过jQuery改变元素的class名,使用的是addClass.removeClass 直接改变元素的css属性值,这种是通过添加styl ...
- Camera Lens Coating
Camera Lens Coating Coating Progress 转换镜头,根据要求进行OEM和设计. 光学元件:望远镜.显微镜.相机和数码相机镜头.放大镜头和远摄镜头.定心镜头.投影镜头.投 ...
- deeplearning搜索空间
deeplearning搜索空间 搜索空间是神经网络搜索中的一个概念.搜索空间是一系列模型结构的汇集, SANAS主要是利用模拟退火的思想在搜索空间中搜索到一个比较小的模型结构或者一个精度比较高的模型 ...
- 大尺寸卫星图像目标检测:yoloT
大尺寸卫星图像目标检测:yoloT 1. 前言 YOLT论文全称「You Only Look Twice: Rapid Multi-Scale Object Detection In Satellit ...
- GPU端到端目标检测YOLOV3全过程(上)
GPU端到端目标检测YOLOV3全过程(上) Basic Parameters: Video: mp4, webM, avi Picture: jpg, png, gif, bmp Text: doc ...