【面试经典 150 | 二分查找】搜索插入位置

news2025/2/27 5:33:41

文章目录

  • 写在前面
  • Tag
  • 题目来源
  • 题目解读
  • 解题思路
    • 方法一:二分查找
      • 闭区间
      • 左闭右开区间
      • 开区间
      • 总结
  • 知识总结
  • 写在最后

写在前面

本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……

专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:

  • Tag:介绍本题牵涉到的知识点、数据结构;
  • 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
  • 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
  • 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
  • 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。

Tag

【二分查找】【数组】


题目来源

35. 搜索插入位置


题目解读

其实就是找出数组中大于等于 target 的最小值所在的位置。


解题思路

在数组中找到第一个大于或者等于 target 值的所在位置,数据量不大,约为 O ( 1 0 4 ) O(10^4) O(104),可以一次遍历查找,也开始使用二分查找来解决。题目要求使用时间复杂度为 O ( l o g n ) O(logn) O(logn) 的算法,那就只能使用二分法来解答了。

方法一:二分查找

二分查找是一种高效的搜索算法,在有序数组的指定区间内根据要求搜索元素,根据当前区间的中点的搜索情况缩短区间,每次搜索都会缩短一半的区间,时间复杂度为 O ( l o g n ) O(logn) O(logn) n n n 为有序数组的长度。

二分查找根据区间的开闭分为以下三种情况:

  • 闭区间;
  • 左闭右开区间;
  • 开区间。

二分查找的区间无论是哪种闭合形式,要关注的 问题 始终是三个:

  • 一是何时退出循环;
  • 二是表示左、右区间的左、右指针如何移动;
  • 三是返回什么。

以下将针对三种二分法的三个问题分别进行分析。

闭区间

闭区间表示搜索的区间是闭合的,初始的闭合区间为 [0, n-1],即指针指向 l = 0, r = n-1

何时退出循环?

当区间为空的时候退出 while 循环,何时区间为空?

l > r 时,指针 l 位于指针 r 右侧已经构不成区间了,退出 while 循环。

因此,此时的 while 循环条件为 l <= r

左、右指针如何移动?

在闭区间情况下,如果 nums[mid] < target,说明 >= target 的值在右侧区间,于是只需要更新左指针 l = mid + 1;否则(nums[mid] >= target)说明 mid 及其之后的位置都是确定大于 target 的,这时候需要更新右指针 r = mid - 1 来判断左区间内的数。

返回什么?

退出循环后,r 指向的位置为 l 指向位置左侧的第一个位置,最后返回 l 或者 r + 1

实现代码

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int n = nums.size();
        int l = 0, r = n - 1;
        while (l <= r) {        // 区间为空退出循环
            int mid = l + ((r - l) >> 1);
            if (nums[mid] < target) {
                l = mid + 1;
            }
            else {
                r = mid - 1;
            }
        }
        return l; // 等价于 return r+1
    }
};

左闭右开区间

左闭右开区间表示搜索的区间是左闭右开的,初始的指针指向为 l = 0, r = n

何时退出循环?

当区间为空的时候退出 while,何时区间为空?

因为 r 指针是取不到的,所以当 l = r 时,区间为空(因为实际的区间左端点为 l,右端点为 r,构不成区间),退出 while 循环。

此时的 while 循环条件为 l < r

左、右指针如何移动?

在左闭右开区间情况下,如果 nums[mid] < target,说明 >= target 的值在右侧区间,于是只需要更新左指针 l = mid + 1;否则(nums[mid] >= target)说明 mid 及其之后的位置都是确定大于 target 的,这时候需要更新右指针 r = mid 来判断左区间即 [l, mid-1] 中的数。

返回什么?

退出循环后,rl 指向的是同一个位置,最后返回 l 或者 r

实现代码

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int n = nums.size();
        int l = 0, r = n;
        while (l < r) {        // 区间为空退出循环
            int mid = l + ((r - l) >> 1);
            if (nums[mid] < target) {
                l = mid + 1;
            }
            else {
                r = mid;
            }
        }
        return l; // 等价于 return r
    }
};

开区间

开区间表示搜索的区间两边都是开的,初始的指针指向为 l = -1, r = n

何时退出循环?

当区间为空的时候退出 while,何时区间为空?

因为 lr 指针指向的值是取不到的,所以当 l + 1 = r 时,(l, r) 表示的区间为空,退出 while 循环。

此时的 while 循环条件为 l + 1 < r

左、右指针如何移动?

在开区间情况下,如果 nums[mid] < target,说明 >= target 的值在右侧区间,于是只需要更新左指针 l = mid(因为左区间是开的,实际的区间是 mid + 1);否则(nums[mid] >= target)说明 mid 及其之后的位置都是确定大于 target 的,这时候需要更新右指针 r = mid 来判断左区间即 [l, mid - 1] 中的数。

返回什么?

退出循环后,l 指向的位置位于 r 指向位置的左侧,最后返回 r 或者 l+1

总结

无论是哪种区间闭合形式,关注的始终是:何时退出while循环、左右指针如何更新以及最后返回什么这三个问题。

需要注意的移动指针一定要保证原来区间的闭合与否:原来区间是闭合的,更新后的指针指向的依旧是闭合的区间;原来区间是开的,更新后的指针指向的依旧是开的区间。

以上三种形式,可以挑选一种自己熟悉的形式记忆,并记住这是解决在有序数组中查找大于等于指定值的代码。


知识总结

在有序数组中查找大于等于指定值的最小位置的二分查找方法是十分经典,该方法已经被封装成了一个函数 lower_bound(),该方法之所以是经典是因为其他类型的查找都可以通过它来完成:

  • 在有序数组中查找大于等于指定值的最小位置,这就不赘述了;
  • 在有序数组中查找大于指定值 x 的最小位置,本题及以下等价转换仅限于整数数组。此时可以等价转化为 “在有序数组中查找大于等于指定值 x+1 的最小位置”;
  • 在有序数组中查找小于指定值 x 的最大位置,可以等价转化为 “在有序数组中查找大于等于指定值 x 的最小位置” 减 1
  • 在有序数组中查找小于等于指定值 x 的最大位置,可以等价转化为 “在有序数组中查找大于等于指定值 x+1 的最小位置” 减 1

写在最后

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。

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

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

相关文章

【Python 训练营】N_14 文件查找和替换

题目 新建一个test3.txt文件&#xff0c;内容如下图&#xff0c;然后从中查找字符串’five’&#xff0c;并统计出现的次数&#xff1b;替换其中的’five’字符串为’python’。 分析 类似Excel中的查找和替换&#xff0c;查找相应内容需用到正则&#xff0c;还考察文件打开、…

持续集成交付CICD:CentOS 7 安装 Sonarqube9.6

目录 一、实验 1.CentOS 7 安装 Sonarqube9.6 二、问题 1.安装postgresql13服务端报错 2.postgresql13创建用户报错 一、实验 1.CentOS 7 安装 Sonarqube9.6 &#xff08;1&#xff09;下载软件及依赖包 ①Sonarqube9.6下载地址 https://binaries.sonarsource.com/Dis…

欧洲各国及发达国家经济支柱和第一出口商品是什么

工业在欧洲各国经济支柱中的表现 一般发达国家&#xff0c;像西欧的国家第三产业即服务业占GDP70%甚至更高&#xff0c;从业人数比重也最大&#xff0c;只是越发达的国家服务业的知识性和科技含量会更高&#xff0c;如商业咨询、律师、医疗卫生、科技服务、商业服务。服务业的…

布隆过滤器,Redis之 bitmap,场景题【如果微博某个大V发了一条消息,怎么统计有多少人看过了】

学习文档 文章目录 一、什么是 Bitmap1-1、Bitmap 相关命令 二、Bitmap 和 Set 对比2-1、数据准备2-2、内存对比2-3、性能对比 三、布隆过滤器3-1、理论3-2、代码实现 四、Java中的 Hash 函数 最近面试时&#xff0c;遇到了一个场景题&#xff0c;面试官问如何统计一条微博大V的…

计算机网络扫盲(1)——因特网

一、概述 因特网是一个世界范围的计算机网络&#xff0c;即它是一个互联了遍及全世界数十亿计算设备的网络。大家对此应该并不陌生&#xff0c;我们身边有着不计其数的计算机设备被接入了因特网&#xff0c;如今计算机网络这个术语似乎已经有点过时了&#xff0c;用因特网的术语…

结合贝叶斯定理浅谈商业银行员工异常行为排查

1.贝叶斯定理的数学表达 贝叶斯方法依据贝叶斯定理。关于贝叶斯定理解释如下&#xff1a;首先我们设定在事件B条件下&#xff0c;发生事件A的条件概率&#xff0c;即 &#xff0c;从数学公式上&#xff0c;此条件概率等于事件A与事件B同时发生的概率除以事件B发生的概率。 上述…

MyBatis增删改查和配置文件

MyBatis增删改查 MyBatis新增 新增用户 持久层接口添加方法 void add(User user);映射文件添加标签 <insert id"add" parameterType"com.mybatis.pojo.User">insert into user(username,sex,address) values(# {username},# {sex},# {address}) <…

海林猴头菇 区域公用品牌形象正式发布

猴头菇是中国八大“山珍”之一&#xff0c;自古就有“山珍猴头&#xff0c;海味燕窝”之说&#xff0c;猴头菇在中国既是食用珍品&#xff0c;又是重要的药用菌。 海林市位于黑龙江省东南部&#xff0c;地处长白山脉张广才岭东麓&#xff0c;素有“林海雪原”之称。 海林猴头菇…

虚函数表和虚函数在内存中的位置

文章目录 结论验证 结论 虚函数表指针是虚函数表所在位置的地址。虚函数表指针属于对象实例。因而通过new出来的对象的虚函数表指针位于堆&#xff0c;声名对象的虚函数表指针位于栈 虚函数表位于只读数据段&#xff08;.rodata&#xff09;&#xff0c;即&#xff1a;C内存模…

《opencv实用探索·八》图像模糊之均值滤波简单理解

1、前言 什么是噪声&#xff1f; 该像素与周围像素的差别非常大&#xff0c;导致从视觉上就能看出该像素无法与周围像素组成可识别的图像信息&#xff0c;降低了整个图像的质量。这种“格格不入”的像素就被称为图像的噪声。如果图像中的噪声都是随机的纯黑像素或者纯白像素&am…

jionlp :一款超级强大的Python 神器!轻松提取地址中的省、市、县

在日常数据处理中&#xff0c;如果你需要从一个完整的地址中提取出省、市、县三级地名&#xff0c;或者乡镇、村、社区两级详细地名&#xff0c;你可以使用一个第三方库来实现快速解析。在使用之前&#xff0c;你需要先安装这个库。 pip install jionlp -i https://pypi.douba…

如何使用注解实现接口的幂等性校验

如何使用注解实现接口的幂等性校验 背景什么是幂等性为什么要实现幂等性校验如何实现接口的幂等性校验1. 数据库唯一主键2. 数据库乐观锁3. 防重 Token 令牌4. redis 如何将这几种方式都组装到一起结语 背景 最近在小组同学卷的受不了的情况下&#xff0c;我决定换一个方向卷去…

Docker Compose及Docker 知识点整理

目录 1、Docker Compose 简介 2、为什么要使用Docker Compose 3、Docker Compose安装使用&#xff08;Linux&#xff09; 3.1 下载 3.2 mkdir docker 文件夹目录 3.3 上传docker-compose到docker文件夹 3.4 移动到 /usr/local/bin 目录下 3.5 添加执行权限 3.6 修改文…

图文深入理解TCP三次握手

前言 TCP三次握手和四次挥手是面试题的热门考点&#xff0c;它们分别对应TCP的连接和释放过程&#xff0c;今天我们先来认识一下TCP三次握手过程&#xff0c;以及是否可以使用“两报文握手”建立连接&#xff1f;。 1、TCP是什么&#xff1f; TCP是面向连接的协议&#xff0c;…

关于Typora如何插入自己的云端视频的方法

关于Typora如何插入自己的云端视频的方法 文章目录 关于Typora如何插入自己的云端视频的方法前言&#xff1a;实现步骤&#xff1a;小结 前言&#xff1a; 我本来使用gitee来作为typora的图床&#xff0c;但我现在想要把我自己的视频上传到云端&#xff0c;然后通过超链接在ty…

2017年全国硕士研究生入学统一考试管理类专业学位联考英语(二)试题

文章目录 Section I Use of EnglishSection II Reading ComprehensionText 121-细节信息题22-细节信息题23-推断题24-细节信息题25-态度题 Text 226-细节信息题27-细节信息题28-细节信息题29-细节信息题30-细节信息题 Text 331-细节信息题32-细节信息题33-猜词题34-细节信息题3…

C语言之位段(详解)

C语言之位段 文章目录 C语言之位段1. 位段的介绍2. 位段的内存分配3. 位段跨平台问题4. 位段的应用5. 位段使用注意 1. 位段的介绍 位段&#xff08;bit-field&#xff09;是C语言中的一种特殊数据类型&#xff0c;它允许将一个字节分成几个部分&#xff0c;并为每个部分指定特…

设计模式-结构型模式之组合、享元设计模式

文章目录 四、组合模式五、享元模式 四、组合模式 组合模式&#xff08;Composite Pattern&#xff09;&#xff0c;又叫部分整体模式&#xff0c;是用于把一组相似的对象当作一个单一的对象。 组合模式依据树形结构来组合对象&#xff0c;用来表示部分以及整体层次。它创建了…

嵌入式Linux:ARM驱动+QT应用+OpenCV人脸识别项目实现

一、前言&#xff1a; 这个项目主要分为两部分&#xff0c;客户端&#xff08;ARM板端&#xff09;负责利用OpenCV采集人脸数据&#xff0c;利用TCP将人脸数据发送给服务器&#xff0c;然后服务器根据人脸数据进行人脸识别&#xff0c;将识别后的结果返还给客户端&#xff0c;客…

【教学类-06-13】20231202 0-9数字分合-房屋样式(二)-左空或者右空-升序-抽7题

作品展示&#xff1a; 背景需求&#xff1a; 【教学类-06-12】20231202 0-9数字分合-房屋样式&#xff08;一&#xff09;-下右空-升序-抽7题-CSDN博客文章浏览阅读102次。【教学类-06-12】20231202 0-9数字分合-房屋样式-下右空-升序https://blog.csdn.net/reasonsummer/arti…