【数组】二分查找(减不减一,看初始化!)

一、力扣习题链接

704. 二分查找 - 力扣(LeetCode)

二、思路

这道题目的前提是数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件,当大家看到题目描述满足如上条件的时候,可要想一想是不是可以用二分法了。

二分查找涉及的很多的边界条件,逻辑比较简单,但就是写不好。

例如到底是 while(left < right) 还是 while(left <= right)

到底是right = middle呢,还是要right = middle - 1呢?

大家写二分法经常写乱,主要是因为对区间的定义没有想清楚,区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。

写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)

一句秒杀:说实话,看完下面的解释我还是一团糟,但是我可以理解的是,如果如果是左闭右开,那么right就要end-1,好的,现在我更改口令:只要初始化-1,代表着父区间右侧-1,所以接下来的子区间右侧都要乖乖听话-1;如果左闭右闭,那么由于初始化不-1,所以middle就不-1;对于所有的左区间,middle通通+1!!!!

2.1左闭右闭

第一种写法,我们定义 target 是在一个在左闭右闭的区间里,也就是[left, right] 

区间的不同决定了二分法代码的不同!

  • while (left <= right) 要使用 <= ,因为left == right是有意义的,所以使用 <=

  • if (nums[middle] > target) 的话,right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1

总结:因为这里是右闭,那么引发的俩个问题:左可等于右,把左闭右开想成原型的话,右闭多了一个元素,所以要-1

例如在数组:1,2,3,4,7,9,10中查找元素2,如图所示:

发现元素在左区间,更新right

发现元素在右区间,更新left

 

classs Solution {
public:int search(vector<int>& nums, int target) {int left = 0;int right = nums.size() - 1; // end指向最后一个元素的下一个位置while (left <= right) { //  必须是<=int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2if (nums[middle] > target) {right = middle - 1; // target 在左区间,所以[left, middle - 1]} else if (nums[middle] < target) {left = middle + 1; // target 在右区间,所以[middle + 1, right]} else { // nums[middle] == targetreturn middle; // 数组中找到目标值,直接返回下标}}// 未找到目标值return -1;}
};

2.2左闭右开

如果说定义 target 是在一个在左闭右开的区间里,也就是[left, right) ,那么二分法的边界处理方式则截然不同。

有如下两点:

  • while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的

  • if (nums[middle] > target) 的话,right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]

在数组:1,2,3,4,7,9,10中查找元素2,如图所示:

 

// 版本二
class Solution {
public:int search(vector<int>& nums, int target) {int left = 0;int right = nums.size(); // [left, right)while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <int middle = left + ((right - left) /2);if (nums[middle] > target) {right = middle; // target 在左区间,在[left, middle)中} else if (nums[middle] < target) {left = middle + 1; // target 在右区间,在[middle + 1, right)中} else { // nums[middle] == targetreturn middle; // 数组中找到目标值,直接返回下标}}// 未找到目标值return -1;}
};

三、小结

二分法是非常重要的基础算法,为什么很多同学对于二分法都是一看就会,一写就废

其实主要就是对区间的定义没有理解清楚,在循环中没有始终坚持根据查找区间的定义来做边界处理。

区间的定义就是不变量,那么在循环中坚持根据查找区间的定义来做边界处理,就是循环不变量规则。

本篇根据两种常见的区间定义,给出了两种二分法的写法,每一个边界为什么这么处理,都根据区间的定义做了详细介绍。

四、拓展练习(35,34,69,367) 

以下为题解

  • 35.搜索插入位置(opens new window)​​​​​​
  • 34.在排序数组中查找元素的第一个和最后一个位置(opens new window)
  • 69.x 的平方根(opens new window)
  • 367.有效的完全平方数(opens new window)

希望给大家带来帮助!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/97702.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

复旦大学EMBA:揭秘科创企业,领略未来战略!

智能制造&#xff0c;国之重器。作为制造强国建设的主攻方向&#xff0c;智能制造的发展水平关系到我国未来制造业在全球的地位与影响力。发展智能制造&#xff0c;是加快建设现代化产业体系的重要手段&#xff0c;提升供给体系适配性的有力抓手&#xff0c;也是建设数字中国的…

css的gap设置元素之间的间隔

在felx布局中可以使用gap来设置元素之间的间隔&#xff1b; .box{width: 800px;height: auto;border: 1px solid green;display: flex;flex-wrap: wrap;gap: 100px; } .inner{width: 200px;height: 200px;background-color: skyblue; } <div class"box"><…

基于SSM的固定资产管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

ROS2 Galactic安装

ROS2 Galactic安装 ROS2 Galactic安装字体编码检查添加ros2仓库到本机安装ROS2系统测试ROS卸载ros2 ROS2 Galactic安装 字体编码检查 安装需要设置本级为UTF-8字体&#xff0c;使用如下指令检查&#xff1a; locale # check for UTF-8sudo apt update && sudo apt …

Acwing.886 求组合数Ⅱ

题目 给定n组询问&#xff0c;每组询问给定两个整数a&#xff0c; b&#xff0c;请你输出 的值。 输入格式 第一行包含整数n。 接下来n行&#xff0c;每行包含—组a和b。 输出格式 共n行&#xff0c;每行输出—个询问的解。 数据范围 1<n≤10000, 1 <b<a≤105…

《C和指针》笔记31:多维数组的数组名、指向多维数组的指针、作为函数参数的多维数组

文章目录 1. 指向多维数组的数组名2. 指向多维数组的指针3. 作为函数参数的多维数组 1. 指向多维数组的数组名 我们知道一维数组名的值是一个指针常量&#xff0c;它的类型是“指向元素类型的指针”&#xff0c;它指向数组的第1个元素。那么多维数组的数组名代表什么呢&#x…

点餐小程序实战教程06-首页开发

用户注册功能开发好了之后&#xff0c;我们就要开发小程序&#xff0c;首先我们是规划小程序的功能模块&#xff0c;我们一共是四个模块&#xff0c;分别是首页、订单、消息和我的。 首页我们主要是点餐的功能&#xff0c;可以选择菜品&#xff0c;加入到购物车&#xff0c;然…

Flink---10、处理函数(基本处理函数、按键分区处理函数、窗口处理函数、应用案例TopN、侧输出流)

星光下的赶路人star的个人主页 我的敌手就是我自己&#xff0c;我要他美好到能使我满意的程度 文章目录 1、处理函数1.1 基本处理函数&#xff08;ProcessFunction&#xff09;1.1.1 处理函数的功能和使用1.1.2 ProcessFunction解析1.1.3 处理函数的分类 1.2 按键分区处理函数&…

剑指offer——JZ34 二叉树中和为某一值的路径(二) 解题思路与具体代码【C++】

一、题目描述与要求 二叉树中和为某一值的路径(二)_牛客题霸_牛客网 (nowcoder.com) 题目描述 输入一颗二叉树的根节点root和一个整数expectNumber&#xff0c;找出二叉树中结点值的和为expectNumber的所有路径。 1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过…

“国产版”的chatgpt国内用户的更优选择!一定要收藏!

众所周知&#xff0c;chatGPT没有对国内开放使用权限&#xff0c;因此国内的用户是不可以使用直接使用chatgpt的&#xff0c;部分朋友想要通过使用网络工具使用其对话服务&#xff0c;这种行为显然是不可取的。其实也有好用的国产版的chatGPT网站&#xff0c;只是大家可能之前没…

深度学习实战基础案例——卷积神经网络(CNN)基于MobileNetV3的肺炎识别|第3例

文章目录 前言一、数据集介绍二、前期工作三、数据集读取四、构建CA注意力模块五、构建模型六、开始训练 前言 Google公司继MobileNetV2之后&#xff0c;在2019年发表了它的改进版本MobileNetV3。而MobileNetV3共有两个版本&#xff0c;分别是MobileNetV3-Large和MobileNetV2-…

【 构建maven工程时,配置了阿里云的前提下,依旧使用中央仓库下载依赖导致失败的问题!】

构建maven工程时&#xff0c;配置了阿里云的前提下&#xff0c;依旧使用中央仓库下载依赖导致失败的问题&#xff01;&#xff01;&#xff01; 错误提示信息: Cannot download ZIP distribution from https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3…

性能监控-微服务链路追踪skywalking搭建

中文文档&#xff1a;hong设置 (skyapm.github.cio) 参考:微服务链路追踪SkyWalking的介绍和部署_skywalking部署_技术闲聊DD的博客-CSDN博客 参考&#xff1a;链路追踪SkyWalking整合项目以及数据持久化_skywalking 持久化_技术闲聊DD的博客-CSDN博客 Liunx部署skywalking以…

云服务仿真:完全模拟 AWS 服务的本地体验 | 开源日报 No.45

localstack/localstack Stars: 48.7k License: NOASSERTION LocalStack 是一个云服务仿真器&#xff0c;可以在您的笔记本电脑或 CI 环境中以单个容器运行。它提供了一个易于使用的测试/模拟框架&#xff0c;用于开发云应用程序。主要功能包括&#xff1a; 在本地机器上完全…

Spring框架(中)

1、基于注解管理Bean&#xff1a; 1、开启组件扫描&#xff1a; Spring 默认不使用注解装配 Bean&#xff0c;因此我们需要在 Spring 的 XML 配置中&#xff0c;通过 context:component-scan 元素开启 Spring Beans的自动扫描功能。开启此功能后&#xff0c;Spring 会自动从扫…

transformer不同的包加载模型的结构不一样

AutoModel AutoModelForTokenClassification 结论&#xff1a; AutoModel加载的模型与AutoModelForTokenClassification最后一层是不一样的&#xff0c;从这个模型来看&#xff0c;AutoModelForTokenClassification加载的结果是对的 问题&#xff1a; 为什么AutoModel和Aut…

使用Docker安装JupyterHub

安装JupyterHub 拉取Jupyter镜像并运行容器 docker run -d -p 8000:8000 --name jupyterhub jupyterhub/jupyterhub jupyterhub # -d&#xff1a;后台运行 # -p 8000:8000&#xff1a;宿主机的8000端口映射容器中的8000端口 # --name jupyterhub&#xff1a;给运行的容器起名…

小谈设计模式(10)—原型模式

小谈设计模式&#xff08;10&#xff09;—原型模式 专栏介绍专栏地址专栏介绍 原型模式角色分类抽象原型&#xff08;Prototype&#xff09;具体原型&#xff08;Concrete Prototype&#xff09;客户端&#xff08;Client&#xff09;原型管理器&#xff08;Prototype Manager…

创建GCP service账号并管理权限

列出当前GCP项目的所有service account 我们可以用gcloud 命令 gcloud iam service-accounts list gcloud iam service-accounts list DISPLAY NAME EMAIL DISABLED terraform …

苹果手机怎么备份所有数据?2023年iPhone 15数据备份常用的3种方法!

当苹果手机需要进行刷机、恢复出厂设置、降级iOS系统等操作时&#xff0c;我们需要将自己的iPhone数据提前进行备份。 特别是在苹果发布新iOS系统时&#xff0c;总有一些小伙伴因为升降级系统&#xff0c;而导致了重要数据的丢失。 iPhone中储存着重要的照片、通讯录、文件等数…