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

引言

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

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.mzph.cn/news/618362.shtml

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

相关文章

009-Zynq基操之如何去玩转PL向PS的中断(对新手友好,走过路过千万不要错过)

文章目录 前言一、PL-PS的中断是啥&#xff1f;二、PL-PS端中断详细步骤1.ZYNQ核配置2.PS端中断函数配置3.需要拓展多个中断函数 总结 前言 本设计跟我的ZYNQ实战合集专栏中的脉冲触发电路有关系&#xff0c;也正好趁这个机会讲述一下PL-PS的中断系统&#xff0c;如何去触发中…

Java 设计模式

1.单例设计模式 对某个类只能存在一个对象实例&#xff0c;并且该类只提供一个取得其对象实例的方法。 1.1 饿汉式 构造器私有化 --> 防止直接new类的内部创建对象提供一个static的public方法 getInstance class GirlFriend {private String name;private static GirlFri…

MySQL第二次

作业要求&#xff1a; 作业代码实现&#xff1a; create database db_04 default charsetutf8mb4;use db_04;create table if not exists t_hero(id int primary key auto_increment,name varchar(20) not null unique,nickname varchar(50) not null unique,address varchar…

【Python机器学习系列】建立KNN模型预测心脏疾病(完整实现过程)

这是Python程序开发系列原创文章&#xff0c;我的第198篇原创文章。 一、问题 对于表格数据&#xff0c;一套完整的机器学习建模流程如下&#xff1a; 针对不同的数据集&#xff0c;有些步骤不适用即不需要做&#xff0c;其中橘红色框为必要步骤&#xff0c;由于数据质量较高&…

4点优势,昂首资本使用浮动差价不使用固定差价的原因

在交易中&#xff0c;很多投资者和昂首资本一样&#xff0c;会使用浮动点差而不使用固定点差&#xff0c;那是因为投资者和昂首资本一样认为&#xff0c;使用浮动差价交易会比使用固定价差交易更有优势。 首先在大部分交易时段&#xff0c;价差缩小。正如投资者和昂首资本所知…

Pandas实战100例 | 案例 40: 分组并应用多个聚合函数

案例 40: 分组并应用多个聚合函数 知识点讲解 Pandas 的 groupby 和 agg 方法使得对数据分组后应用多个聚合函数成为可能。这在数据分析中非常有用&#xff0c;可以快速得到分组统计数据。 分组聚合: 使用 groupby 方法对数据进行分组。多重聚合: 使用 agg 方法并传递一个包…

用python批量合并word文件并统一调整图片大小

import os,time from docx import Document from docxcompose.composer import Composer import win32com.client as win32 # 获取要处理的文件夹路径 folder_path r"C:\Users\Thinkpad\Desktop\wordoutput" datanames os.listdir(folder_path) list_wordoutname …

6. 逻辑删除

逻辑删除对应的是物理删除&#xff0c;分别介绍一下这两个概念&#xff1a; 物理删除 &#xff1a;指的是真正的删除&#xff0c;即&#xff1a;当执行删除操作时&#xff0c;将数据表中的数据进行删除&#xff0c;之后将无法再查询到该数据逻辑删除 &#xff1a;并不是真正意…

SQL 解析与执行流程

一、前言 在先前的技术博客中&#xff0c;我们已经详细介绍过数据库的 parser 模块与执行流程&#xff1a;用户输入的 SQL 语句通过词法解析器生成 token&#xff0c;再通过语法分析器生成抽象语法树&#xff08;AST&#xff09;&#xff0c;经过 AST 生成对应的 planNode&…

JavaScript常用事件详解

一、用于form&#xff08;表单&#xff09;的事件 在网页中经常会遇到一些表单的验证&#xff0c;是通过事件进行处理的&#xff0c;比如用户输入用户名之后&#xff0c;及时显示用户是否被注册 用于form&#xff08;表单&#xff09;的事件 事件名功能 onblur 当元素失…

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

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

go 语言优雅地处理 error

我看到很多 golang 社区的开发者&#xff0c;特别是因为它的简单性而被吸引的开发者&#xff0c;对 golang 中的事情应该如何处理做出了一些快速的判断。 其中一件事就是错误处理。由于目前大多数语言的开发者都来自于 OOP 背景&#xff0c;他们习惯于处理异常&#xff0c;或者…

go最佳实践:如何舒适地编码

什么是 "最佳 "做法&#xff1f; 有很多做法&#xff1a;你可以自己想出来&#xff0c;在互联网上找到&#xff0c;或者从其他语言中拿来&#xff0c;但由于其主观性&#xff0c;并不总是容易说哪一个比另一个好。”最佳”的含义因人而异&#xff0c;也取决于其背景…

数据结构学习之顺序栈应用的案例(有效的括号)

实例要求&#xff1a; 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效&#xff1b; 有效字符串需满足的条件&#xff1a; 1、左括号必须用相同类型的右括号闭合&#xff1b; 2、左括号必须…

CSAPP - 流程化的人工反汇编 string_length, strings_not_equal

文章目录 反汇编的流程string_length 的反汇编&#xff0c;第二次尝试strings_not_equal 反汇编&#xff0c;第二次尝试一些“定式”的整理定式1&#xff1a; cmp 和 je/jne定式2&#xff1a;test A,A 和 je/jne 反汇编的流程 依然是 CSAPP bomblab phase_1 的小白视角的理解。…

c# ref和out参数修饰符

ref&#xff1a;把值类型变成引用类型传递&#xff0c;形参的值改变了实参的值也会改变 public static int findMax(ref int num1, ref int num2){num1 * 2;num2 * 2;return num1 num2;}private static void Main(string[] args){int a1 1; int a2 2;findMax(ref a1, ref a2…

什么是算法的空间复杂度?

一、问题 常常⽤算法的空间复杂度来评价算法的性能&#xff0c;那么什么是算法的空间复杂度呢&#xff1f; 二、解答 算法的空间复杂度是指在算法的执⾏过程中&#xff0c;需要的辅助空间数量。 辅助空间数量指的不是程序指令、常数、指针等所需要的存储空间&#xff0c;也不是…

Pandas实战100例 | 案例 41: 字符串操作

案例 41: 字符串操作 知识点讲解 Pandas 提供了强大的字符串处理功能&#xff0c;这些功能类似于 Python 的标准字符串方法。你可以对 DataFrame 中的字符串数据执行各种操作&#xff0c;如分割、提取、计算长度等。 字符串分割: 使用 str.split() 分割字符串。提取字符串: …

【面试合集】1.说说你对微信小程序的理解?优缺点?

面试官&#xff1a;说说你对微信小程序的理解&#xff1f;优缺点&#xff1f; 一、是什么 2017年&#xff0c;微信正式推出了小程序&#xff0c;允许外部开发者在微信内部运行自己的代码&#xff0c;开展业务 截至目前&#xff0c;小程序已经成为国内前端的一个重要业务&…

NPM进阶知识与用法详解(二)

文章目录 一、NPM高级用法1. NPM模块发布与私有模块管理2. NPM钩子函数3. NPM包管理与优化 二、NPM与现代化前端工具链1. NPM与Yarn、PNPM的比较2. NPM在Webpack、Vite等构建工具中的应用3. NPM与Monorepo架构 三、总结与展望1. 前端包管理工具发展趋势2. 提高NPM使用效率的建议…