二分查找算法(2) _在排序数组中查找元素的第一个和最后一个_模板

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

二分查找算法(2) _在排序数组中查找元素的第一个和最后一个_模板

收录于专栏【经典算法练习】
本专栏旨在分享学习算法的一点学习笔记,欢迎大家在评论区交流讨论💌

目录

1. 题目链接:

2. 题目描述 :

3. 解法 :

    解法一:暴力枚举遍历:

    算法思路 :

    代码展示 :

    结果分析 :

    解法二: 二分查找 :

    算法思路 :

    细节处理:

查找区间的左端点

1. 循环条件

2. 求终点的操作 

 查找区间的右端点 

1. 循环条件

2. 求终点的操作 

    代码展示 :

    结果分析 :

4. 二分算法模板总结


1. 题目链接:

OJ链接: 在排序数组中查找元素的第一个和最后一个

2. 题目描述 :

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [5,7,7,8,8,10]
, target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10]
, target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

提示:

  • 0 <= nums.length <= 105
  • -109 <= nums[i] <= 109
  • nums 是一个非递减数组
  • -109 <= target <= 109

3. 解法 :

    解法一:暴力枚举遍历:

    算法思路 :

使用两个头尾指针遍历整个数组,在排序数组中查找元素的第一个和最后一个

    代码展示 :

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {int left = 0, right = nums.size() - 1;while(left < right){if(nums[left] < target) left++;else if(nums[right] > target) right--;else break;}if(left <= right && nums[left] == target && nums[right] == target)return {left, right};else return{-1, -1};}
};

 

    结果分析 :

题目顺利通过!时间复杂度为: O(N),不过算法还有进一步优化的空间.

    解法二: 二分查找 :

    算法思路 :

a.分析插⼊位置左右两侧区间上元素的特点:
设插⼊位置的坐标为 index ,根据插⼊位置的特点可以知道:
        •[left, index - 1] 内的所有元素均是⼩于 target 的;
        •[index, right] 内的所有元素均是⼤于等于 target 的。

b.设 left 为本轮查询的左边界, right 为本轮查询的右边界。根据 mid 位置元素的信
息,分析下⼀轮查询的区间:
        ▪ 当 nums[mid] >= target 时,说明 mid 落在了[index, right] 区间上,
        mid 左边包括 mid 本⾝,可能是最终结果,所以我们接下来查找的区间在[left,
        mid] 上。因此,更新 right 到 mid 位置,继续查找。
        ▪ 当 nums[mid] < target 时,说明 mid 落在了[left, index - 1] 区间上,
       mid 右边但不包括 mid 本⾝,可能是最终结果,所以我们接下来查找的区间在[mid
        + 1, right] 上。因此,更新 left 到 mid + 1 的位置,继续查找。

c.直到我们的查找区间的⻓度变为 1 ,也就是 left == right 的时候, left 或者
    right 所在的位置就是我们要找的结果。

总结:

查找区间左端点 --- [..., target) [target, ...]

1. nums[mid] < t left  = mid + 1

2. nums[mid] >= t right = mid

 

 查找区间右端点 --- [..., target] (target, ...]

1. nums[mid] <= t left  = mid

2. nums[mid] > t right = mid - 1

 

    细节处理:

查找区间的左端点
1. 循环条件

while(left < right)

注意这里不能使用while(left <= right) 

1. 有结果: 当我们的left == right时,我们的left即是我们的结果,但如果你是使用while(left <= right) 循环,程序会陷入死循环,因为此时right + left / 2 = right/left

2. 全部大于target: 那我们的right会一直往左走,直到left与right相遇,这时候我们只需要判断它们相遇点的值是否等于target就行,相反使用while(left <= right)循环,程序依旧陷入死循环

3. 全部小于target: 那我们的left会一直往右走,与情况2是一样的

2. 求终点的操作 

left + (right - left) / 2

注意这里不能使用left + (right - left + 1) / 2

当我们判断只剩下两个元素时,left指向第一个元素, right指向第二个元素

1. mid = left + (right - left) / 2 = left

2. mid = left + (right - left + 1) / 2 = right

        当nums[mid]  < target

                1: left = mid + 1 =right 循环成功结束

                2: left = mid + 1 = right + 1成功错过

        当nums[mid] >= target 

                1: right = mid right == left 循环成功结束

                2: right = mid 死循环

 查找区间的右端点 
1. 循环条件

while(left < right)

 原理和查找区间的左端点的一样

2. 求终点的操作 

left + (right - left + 1) / 2 

注意这里不能使用left + (right - left) / 2

当我们判断只剩下两个元素时,left指向第一个元素, right指向第二个元素

1. mid = left + (right - left) / 2 = left

2. mid = left + (right - left + 1) / 2 = right

        当nums[mid]  <= target

                1: left = mid  死循环

                2: left = mid left== right + 1 循环成功结束

        当nums[mid] > target 

                1: right = mid - 1 right == left - 1循环成功错过

                2: right = mid - 1 right == left 循环成功结束

    代码展示 :

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {if(nums.size() == 0) return {-1, -1};//找左端点 --- [..., target) [target, ...] int left = 0, right = nums.size() - 1, begin = 0;while(left < right){int mid = left + (right - left) / 2;if(nums[mid] >= target)  right = mid;else left = mid + 1;}if(nums[left] == target) begin = left;else return {-1, -1};//找右端点 --- [..., target] (target, ...]left = 0, right = nums.size() - 1;while(left < right){int mid = left + (right - left + 1) / 2;if(nums[mid] <= target) left = mid;else right = mid - 1;  }return {begin, right};}
};

 

    结果分析 :

这里一定要注意细节问题,不然程序很容易死循环

4. 二分算法模板总结

while(left < right){int mid = left + (right - left) / 2;if(...) left = mid + 1;else right = mid;
}while(left < right){int mid = left + (right - left + 1) / 2;if(...) left = mid;else right = mid - 1;
}

快速记忆:

分类讨论的代码,就题论题即可

下面出现-1,上面就+1,否侧不加 

 

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

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

相关文章

NLP-transformer学习:(7)evaluate实践

NLP-transformer学习&#xff1a;&#xff08;7&#xff09;evaluate 使用方法 打好基础&#xff0c;为了后面学习走得更远。 本章节是单独的 NLP-transformer学习 章节&#xff0c;主要实践了evaluate。同时&#xff0c;最近将学习代码传到&#xff1a;https://github.com/Mex…

【Linux篇】网络编程基础(笔记)

目录 一、服务器模型 1. C/S 模型 2. P2P模型 二、服务器编程框架 1. I/O处理单元 2. 逻辑单元 3. 网络存储单元 4. 请求队列 三、网络编程基础API 1. socket 地址处理 API &#xff08;1&#xff09;主机字节序和网络字节序 &#xff08;2&#xff09;通用socket地…

【计网】从零开始掌握序列化 --- JSON实现协议 + 设计 传输\会话\应用 三层结构

唯有梦想才配让你不安&#xff0c; 唯有行动才能解除你的不安。 --- 卢思浩 --- 从零开始掌握序列化 1 知识回顾2 序列化与编写协议2.1 使用Json进行序列化2.2 编写协议 3 封装IOService4 应用层 --- 网络计算器5 总结 1 知识回顾 上一篇文章我们讲解了协议的本质是双方能够…

4--SpringBoot项目中分类管理

目录 新增分类 分类分页查询 启用禁用分类 根据类型查询 修改分类 本文介绍SpringBoot项目中的分类管理&#xff0c;操作类似员工管理模块&#xff0c;具体详解可见以下博客&#xff0c;此处给出各部分代码 2--SpringBoot项目中员工管理 详解&#xff08;一&#xff09;-C…

基尔霍夫衍射理论

一、矢量理论到标量理论 前提条件:介质同时具有线性、各向同性、均匀性且无色散。 结论:电场和磁场的所有分量的行为完全相同,可由单一的一个标量波动方程描述,标量理论可以完全准确的代替矢量理论。 若介质不具备上述前提,则用标量理论来表征矢 量理论就会引入误差。 …

面试题 02.07. 链表相交 双指针

面试题 02.07. 链表相交 已解答 简单 相关标签 相关企业 提示 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证…

数业智能心大陆:职场倦怠的新解法

什么是职业倦怠&#xff1f; 在职场中&#xff0c;职业倦怠的表现形式丰富多样。从数业智能心大陆 AI 心理咨询平台的数据来看&#xff0c;职业倦怠呈现出多种状态。教师可能对教学不再满怀热情&#xff0c;精心备课也成为过去式&#xff1b;情绪上容易烦躁、易怒&#xff0c;在…

Elasticsearch不停机切换(上云)方案

如何给飞行中的飞机换引擎? 背景 业务背景 略 技术背景 线下集群40个索引左右&#xff0c;总数据量不大,不到100G因为ES承担的业务鉴权业务&#xff0c;所以不能接受停机割接 还有就是ES中数据来自各个业务方&#xff0c;推送的时机不定&#xff0c;也没有完备的重推机制&…

心理辅导系统的现代化:Spring Boot解决方案

1绪 论 1.1研究背景 随着计算机和网络技术的不断发展&#xff0c;计算机网络已经逐渐深入人们的生活&#xff0c;网络已经能够覆盖我们生活的每一个角落&#xff0c;给用户的网上交流和学习提供了巨大的方便。 当今社会处在一个高速发展的信息时代&#xff0c;计算机网络的发展…

MySQL --数据类型

文章目录 1.数据类型分类2.数值类型2.1 tinyint类型2.2 bit类型2.3小数类型2.31float2.32decimal 3.字符串类型3.1 char3.2varchar3.3 char和varchar比较 4.日期和时间类型5.enum和set 1.数据类型分类 2.数值类型 2.1 tinyint类型 数值越界测试&#xff1a; create table tt1…

Python画笔案例-056 绘制正方形金字塔

1、绘制正方形金字塔 通过 python 的turtle 库绘制 正方形金字塔,如下图: 2、实现代码 绘制正方形金字塔,以下为实现代码: """正方形金字塔.py """ import turtledef draw_square(length):for _ in

设计模式之组合模式例题

答案&#xff1a;C A 知识点&#xff1a;组合模式的意图&#xff1a;将对象组合成树型结构以表示“整体-部分”的层次结构&#xff0c;使得用户对单个对象和组合对象的使用具有一致性

数据挖掘实战-基于SARIMA时间序列模型预测阿里巴巴股票数据趋势

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

android kotlin Extension扩展函数

1、新建一个kt文件&#xff1a; 2、代码&#xff1a; class User(var name:String)/**扩展函数**/ fun User.Print(){print("用户名 $name") }// 扩展函数 swap,调换不同位置的值 fun MutableList<Int>.swap(index1: Int, index2: Int) {val tmp this[index1…

新手必看:一步步教你绑定常见邮箱到第三方应用(如何绑定QQ、163、Hotmail、Gmail等邮箱)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 邮箱绑定 📒📫 QQ邮箱📫 163邮箱📫 Hotmail邮箱📫 Gmail邮箱📫 Yahoo邮箱📫 iCloud邮箱📫 其他邮箱⚓️ 相关链接 ⚓️📖 介绍 📖 你是否曾经为绑定第三方邮箱而感到困惑?你不是一个人!许多人在尝试将QQ邮…

Linux进程概念1

前言 从这篇博客开始&#xff0c;后面我们主要讲xshell中Linux内容&#xff0c;C后续会继续补充一点 Linux基础内容我就不讲了&#xff0c;直接从进程开始讲 1. 进程是什么 像这种程序正在运行&#xff0c;还没有结束的过程就是一个进程&#xff0c;进程在电脑底部就是.exe文…

vscode 顶部 Command Center,minimap

目录 vscode 顶部 Command Center 设置显示步骤: minimap设置 方法一:使用设置界面 方法二:使用命令面板 方法三:编辑 settings.json 文件 左侧目录树和编辑器字体不一致: vscode 顶部 Command Center Visual Studio Code (VSCode) 中的 Command Center 是一个集中…

11年408考研真题解析-计算机网络

第一题&#xff1a; 解析&#xff1a;网络层虚电路服务和数据报服务 传输服务只有&#xff1a;有连接可靠和无连接不可靠两种&#xff0c;直接排除BC。 网络层指的是IP协议&#xff0c;由图二可知&#xff1a;运输层&#xff0c;网际层&#xff0c;网络接口层唯一有连接可靠的协…

vue3 本地windows下的字体的引用

1、先上了张效果&#xff1a; 2、windows 字体的路径&#xff1a;c:/windows/fonts/ 我们用华文行楷来测试下&#xff0c;先将华文行楷拷贝到/src/assets/fonts目录下。 3、然后我们来定义css&#xff1a; font-face {font-family: fyxk;font-style: normal;src: local(Opensan…

图结构感知的Transformer:一种新的图表示学习方法

人工智能咨询培训老师叶梓 转载标明出处 尽管图神经网络&#xff08;GNNs&#xff09;在处理图数据方面取得了显著成就&#xff0c;但它们在表达能力和捕获长距离依赖方面存在局限性。为了突破这些局限&#xff0c;研究者们开始探索将Transformer架构应用于图表示学习。在此基…