二分搜索边界问题的简单结论

引言

二分搜索是一个说简单也很简单(代码很固定,也没几行),说难也很难(边界问题可能会让人想不太清楚)。
事实上,边界问题也是是算法题中普遍存在的难点。
这篇文章讲两个简单的结论,来轻松解决二分搜索算法中的两个边界问题。

Demo1

    /*** 普通二分搜索java实现* 在数组nums中找target。如果能找到,返回数组下标。如果找不到返回-1* @param nums      搜索对象* @param target    目标值* @return*/public int search(int[] nums, int target) {int left = 0;int right = nums.length - 1;while(left <= right) {int mid = left + (right - left >> 1);//等效:int mid = (left + right)/2if (target < nums[mid]) {right = mid - 1;} else if (target > nums[mid]) {left = mid + 1;} else {return mid;}}return -1;}

这是二分搜索最基础的一段代码。
虽然很简单,但这却是所有二分搜索的基本逻辑。大部分变体都和上面这段代码大差不差。
但其中的边界问题需要想清楚。

循环边界问题

  • 定义右指针时,右边界是开还是闭?
    int right = nums.length;
    or
    int right = nums.length - 1;
  • 循环要不要等号?
    while(left <= right)
    or
    while(left < right)

这里给一个一劳永逸的答案,就按照上面的demo,选择:左闭右闭
原因很简单:两边都有效,最容易思考
当选择左闭右闭后,while循环就得加上等号
因为:如果选择不加等号,假如数组里只有一个元素,此时根本无法进入while循环。

Demo2

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。
如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(log n) 的算法。

这个题也不难,很多人都能做出来。
但多少人能肯定自己在做这个题时候没有“猜”的成分?
可以肯定的给出一个让人信服且易于理解的解释。

循环结束,两个指针停在哪里

这个题可以分为两部分:

  1. 能找到target,就像demo1那样:通过mid匹配上target,然后直接返回。此时我们确实不需要关心最后左右指针停在哪里,如下图所示(mid直接找到了绿色的target)
    在这里插入图片描述
  2. target不存在。这是这个题的关键难点所在。
    虽然我们大致知道写出来的最终代码和上面的demo区别依然不大,但是是+1还是-1,是谁+1?left+1? right+1? or mid+1?这个边界问题就有点让人头疼了。
    假如我们知道左右指针最终停的位置,这个问题就会被大大简化。

直接给出结论:左右指针停在“这个不存在的target”的右左两边。如下图所示
在这里插入图片描述
绿色的target并不存在,也就是说两个指针其实是前后挨着的,中间并没有元素,只不过 左指针在右边,右指针在左边。

依据这样一个简单的结论,解决上面的问题就很简单了,一目了然:当target不存在时,left指针的位置就是大于target的最小值

Demo2答案

public int searchInsert(int[] nums, int target) {int start = 0;int end = nums.length-1;while (start <= end) {int mid = ((end - start) >> 1) + start;if (nums[mid] == target) {return mid;} else if (nums[mid] > target) {end = mid - 1;} else {start = mid + 1;}}return start;}

根据这个直观的直观的简单结论,还可以轻松解决很多二分搜索是变体问题。

注意两端别越界

  1. target比最小的值还小时:
    在这里插入图片描述
    此时right就越界了。如果最终要使用right,可能就需要先判断一下。
  2. target比最大的值还大:
    在这里插入图片描述
    此时left越界,同样在使用时要注意判断。
    其实Demo2返回的就是left,为什么不担心越界?
    因为题目的要求是:
    如果目标值不存在于数组中,返回它将会被按顺序插入的位置
    如果target很大,超过了所有值,需要返回的就是n。

为什么

通过观察Demo的执行逻辑,我们可以发现。
如果target不存在,必然会循环到结束。而在最后一次循环中,当left==right,此时两个指针所在的值 无论比target大还是比 target小,下一步肯定有一个指针要再挪动一步。如图所示
在这里插入图片描述

总结

  • 二分法固定写法:左闭右闭,while加等号
  • 当target不存在时,左右指针最终停在“target的右左两边”

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

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

相关文章

python 文件夹中 __init__.py

common文件夹下有&#xff1a;project&#xff0c;__init__.py&#xff0c;common1.py project文件夹内有&#xff1a;__init__.py&#xff0c;p.py common文件夹里&#xff0c;project文件夹 各放了一个 __init__.py 这样就可以在p.py内用from导入common1.py内的代码 # p…

数据挖掘实战-基于机器学习的电商文本分类模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

互联网资讯精选:科技爱好者周刊 | 开源日报 No.145

ruanyf/weekly Stars: 37.4k License: NOASSERTION 记录每周值得分享的科技内容&#xff0c;提供大量就业信息。欢迎投稿、推荐或自荐文章/软件/资源&#xff0c;并可通过多种方式进行搜索。 提供丰富的科技内容每周更新可以提交工作/实习岗位支持投稿和推荐功能 GyulyVGC/…

20240106----重返学习-在VMware里给centos7设置静态IP地址

在VMware里给centos7设置静态IP地址 场景 学习nginx中&#xff0c;想要设置静态IP地址&#xff0c;以便让win10主环境中的Xshell里能够连接到VMware中的CentOS7上&#xff0c;进而可以在Xshell里进行操作。可以做到如复制粘贴之类的&#xff0c;而不是在虚拟机中的默认终端上…

第一个 OpenGL 程序:旋转的立方体(VS2022 / MFC)

文章目录 OpenGL API开发环境在 MFC 中使用 OpenGL初始化 OpenGL绘制图形重置视口大小 创建 MFC 对话框项目添加 OpenGL 头文件和库文件初始化 OpenGL画一个正方形OpenGL 坐标系改变默认颜色 重置视口大小绘制立方体使用箭头按键旋转立方体深度测试添加纹理应用纹理换一个纹理 …

初识 Elasticsearch 应用知识,一文读懂 Elasticsearch 知识文集(1)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

LLaMA-Factory添加adalora

感谢https://github.com/tsingcoo/LLaMA-Efficient-Tuning/commit/f3a532f56b4aa7d4200f24d93fade4b2c9042736和https://github.com/huggingface/peft/issues/432的帮助。 在LLaMA-Factory中添加adalora 1. 修改src/llmtuner/hparams/finetuning_args.py代码 在FinetuningArg…

GB28181视频汇聚平台EasyCVR级联后,部分通道视频无法播放是什么原因?

GB28181协议智慧安防平台EasyCVR是基于各种IP流媒体协议传输的视频汇聚和融合管理平台。视频流媒体服务器EasyCVR采用了开放式的网络结构&#xff0c;支持高清视频的接入和传输、分发&#xff0c;平台提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制…

Python--闭包

在 Python 中&#xff0c;闭包是一种函数&#xff0c;它能够记住并访问其所在词法作用域&#xff08;即定义该函数的作用域&#xff09;中的变量&#xff0c;即使该函数在其词法作用域之外被调用。要形成闭包&#xff0c;需要满足以下几个条件&#xff1a; 必须有一个内嵌函数&…

【AI视野·今日Sound 声学论文速览 第四十三期】Mon, 8 Jan 2024

AI视野今日CS.Sound 声学论文速览 Mon, 8 Jan 2024 Totally 6 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers MusicAOG: an Energy-Based Model for Learning and Sampling a Hierarchical Representation of Symbolic Music Authors Yikai Qian, Tia…

API对象上千个,有啥关联性,kubectl-tree一键搞定

关注【云原生百宝箱】公众号&#xff0c;获取更多云原生消息 "kubectl-tree 是一款强大的 kubectl 插件&#xff0c;通过 ownerReferences 实现 Kubernetes 对象之间的所有权关系探索。相较于 kubectl lineage&#xff0c;它不仅更全面理解 API 对象的逻辑关系&#xff0c…

若依实现前段后登录密码加密

若依虽然有加密解密功能&#xff0c;然后只有前端有&#xff0c;在用户点击保存密码的时候&#xff0c;会将密码保存到本地&#xff0c;但是为了防止密码泄露&#xff0c;所以在保存的时候&#xff0c;进行加密&#xff0c;在回显密码的时候进行解密显示&#xff0c;用户在登录…