【二分查找】--- 进阶题目赏析
Welcome to 9ilk's Code World

(๑•́ ₃ •̀๑) 个人主页: 9ilk
(๑•́ ₃ •̀๑) 文章专栏: 算法Journey
本篇博客我们继续来了解一些有关二分查找算法的进阶题目。
🏠 寻找峰值
📌 题目内容
162. 寻找峰值 - 力扣(LeetCode)
📌 题目解析
- 与山脉数组那道题不同的是,本题数组内存在多个峰值。
- 注意本题一个规定,即num[-1] = num[n] = 负无穷,数组边界都是最小负无穷。
📌算法原理
📒 思路一:暴力解法

有三种情况下,某个数是峰值,我们暴力解法只需要遍历一遍数组进行分类情况即可,但是时间复杂度是O(N)不符合题意。
📒 思路二:二分查找

我们发现:
1. 当arr[i] > arr[i+1]时,此时左边区域一定存在峰值,因此我们要向左缩小范围。
2.当arr[i] < arr[i+1]时,此时右边区域一定存在峰值,因此我们要向右缩小范围。
3.由于峰值位置的不确定我们需要寻找峰值,因此在寻找峰值的过程中,我们发现了二段性因此可以使用二分查找。
二分过程:
1. arr[i] > arr[i+1] ---> right = mid , 此时mid处可能就是峰值所以不能跳过mid。
2. arr[i] < arr[i+1] ---> left = mid +1 ,此时mid+1处才可能是峰值,因此可以跳过mid。
参考代码:
class Solution
{public:int findPeakElement(vector<int>& nums) {int left = 0;int right = nums.size()-1;while(left < right){int mid = left + (right - left ) / 2;if( nums[mid] < nums[mid+1]){left = mid + 1 ;}elseright = mid;}return left;}};
🏠 寻找旋转排序数组中的最小值
📌 题目内容
153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)
📌 题目内容
- 注意题目数组中的数字各不相同。
📌算法原理
📒 思路一:暴力解法
暴力解法思路很简单,可以定义一个min变量,遍历一遍数组,遇到比他小的就更新min,时间复杂度是O(N),并不符合题目要求。
📒 思路二:二分查找

题目要我们找旋转排序数组中的最小值,这个位置是“确定”的,整个数组的大小变化趋势如上图。以D为参考点,我们发现:
1. 最小值所在位置的左边,都是严格大于等于数组最后一个数的。
2.最小值所在位置的右边,都是小于等于数组最后一个数的。
3.本题要我们求的很明显地划分了两段区间,体现了二段性,我们要做的是思考如果mid落在划分的两段区间内,我们如何靠近目标。
二分流程:
1. 当nums[mid] > nums[n-1]时,说明mid处于AB段,此时我们需要向右缩小范围,left = mid+1.
2.当nums[mid] <= nums[n-1]时,说明mid位于CD段,此时我们需要向左缩小范围,由于目标在CD段上,因此更新right时我们不能跳过mid因为mid可能就是最小值。
参考代码:
class Solution {
public:int findMin(vector<int>& nums) {int left = 0;int right = nums.size() - 1;while(left < right){int mid = left + (right - left) / 2;if(nums[mid] < nums[right])right = mid;else left = mid+1;}return nums[left]; }};
思考:我们划分两端区间是以D为参考点,那么我们是否能以A为参考点呢?
1. A~B段是大于等于nums[0](A点)的,而C~D段是严格小于nums[0]的。
2.此时二分流程:
A - B : nums[i]>=nums[0] --> left= mid +1;
C - D : nums[i] < nums[0] --> right = mid;
3.当旋转数组旋转到原来升序时:此时A点就是最小值,区间不断向右,此时就会丢掉最小值,因此对于这种边界情况我们需要特殊处理。
class Solution {
public:int findMin(vector<int>& nums) {int left = 0;int right = nums.size() - 1;if(nums[0] < nums[right])return nums[0];int x = nums[0]; //以A为参照while(left < right){int mid = left + (right - left) / 2;if(nums[mid] >= x )left = mid + 1;else right = mid;}return nums[left]; }};
🏠 0~n-1中缺失的数字
📌 题目内容
LCR 173. 点名 - 力扣(LeetCode)
📌 题目内容
- 注意:对于[0,1,2,3,4]这样的数组,此时缺失的数字应该为5.
📌算法原理
📒 思路一:哈希表
由于缺了一个数字,因此总的人数为数组元素个数+1,此时我们先遍历一遍数组进行映射,再从0-N遍历,没有映射的就是缺失的数字。
class Solution {
public:int takeAttendance(vector<int>& records) {unordered_map<int,int> mp;for(const auto& e : records){mp[e]++;}int reasult = 0;int n = records.size() + 1; for(int i = 0 ; i < n ; i ++){if(mp[i] == 0){reasult = i;break;}}return reasult;}
};
📒 思路二:直接遍历找结果
由于学号从0开始,因此数组中每个数都应该与下标相同,由于缺失了一个数,可能导致它的下一个数占它的位置,也可能他就是最后一个数。
class Solution {
public:int takeAttendance(vector<int>& records) {bool flag = false;int i = 0;for( i = 0 ; i < records.size();i++){if(i != records[i]){flag = true;break;}}return i;}
};
📒 思路三:位运算
既然知道应到同学的人数n,又根据按位异或a^a = 0 的性质,我们可以用ret遍历一遍数组进行异或,再从0-N异或,最后ret就是缺失的数字。
class Solution {
public:int takeAttendance(vector<int>& records) {int n = records.size();int sum = 0;for(int i = 0 ;i <= n ;i++){sum ^= i;}for(int i = 0; i < records.size();i++){sum ^= records[i];}return sum;}
};
📒 思路四:高斯求和公式
由于我们知道了应到学生人数,因此我们可以用等差数列求原本应该的学号之和,再遍历数组减去,最后得到的就是缺失的数字。
class Solution {
public:int takeAttendance(vector<int>& records) {int n = records.size() + 1;int sum = 0 + (n*(n-1)) / 2;cout << sum <<endl;for(int i = 0; i < records.size();i++){sum -= records[i];}return sum;}
};
📒 思路五:二分查找
前面的思路都很简单,但时间复杂度都是O(N)。仔细观察我们发现因为缺失了数字,会造成二段性。

我们发现,由于缺失了一个数字造成了二段性:
1. 左边一段区间的值都与下标相同,而右边一段区间的值与下标不匹配,因此我们需要去靠近第一个不与下标匹配的值。此时这个值的下标就是缺失的数字。
2.nums[mid] = mid时,说明mid在左边,此时需要向右缩小范围。
3.nums[mid] ≠ mid时,说明mid在右边,此时mid可能就是我们要找的,因此不能跳过mid.
4.需要注意的是对于类似[0,1,2,3,4]这样的情况,最后left==right时,我们需要返回left+1.
参考代码:
class Solution {
public:int takeAttendance(vector<int>& records) {int left = 0;int right = records.size() - 1;while(left < right){int mid = left + (right - left ) / 2;if(records[mid] == mid)left = mid + 1;elseright = mid; }if(records[left] != left) return left;return left + 1; }
};
总结:
1. 当题目很明确要求的目标能划分二段性时,我们需要考虑的是在划分区间内怎么接近目标。
2.当不是很明确二段性时,我们要考虑的是在找目标的过程中能否发现二段性。
相关文章:
【二分查找】--- 进阶题目赏析
Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏: 算法Journey 本篇博客我们继续来了解一些有关二分查找算法的进阶题目。 🏠 寻找峰值 📌 题目内容 162. 寻找峰值 - 力扣&#…...
CSS 对齐
CSS 对齐 在网页设计中,CSS(层叠样式表)对齐是一种基本而重要的技术,它决定了网页元素的位置和布局。CSS 提供了多种对齐方法,可以精确控制元素的水平、垂直对齐,以及相对于其父元素或整个页面的位置。本文…...
暑假算法刷题日记 Day 10
目录 重点整理 054、 拼数 题目描述 输入格式 输出格式 输入输出样例 核心思路 代码 055、 求第k小的数 题目描述 输入格式 输出格式 输入输出样例 核心思路 代码 总结 这几天我们主要刷了洛谷上排序算法对应的一些题目,相对来说比较简单 一共是13道…...
【Midjourney】AI作画提示词工程:精细化技巧与高效实践指南
文章目录 💯AI作画提示词基础结构1 图片链接1.1 上传流程 2 文字描述3 后置参数 💯AI作画提示词的文字描述结构1 主体主体细节描述2 环境背景2.1 环境2.2 光线2.3 色彩2.4 氛围 3 视角4 景别构图5 艺术风格6 图片制作方法7 作品质量万能词 💯…...
C语言——文件
文件操作 概念 文件是指存储在外存储器上(一般代指磁盘,也可以是U盘,移动硬盘等)的数据的集合。 文件操作体现在哪几个方面 1.文件内容的读取 2.文件内容的写入 数据的读取和写入可被视为针对文件进行输入和输出的操作…...
视频孪生技术在智慧水利(水务)场景中的典型应用展示
一、智慧水利建设规划 根据水利部编制《“十四五”智慧水利建设规划》,建设数字孪生流域、“2N”水利智能业务应用体系、安全可控水利网络安全防护体系、优化健全水利网信保障体系,建成七大江河数字孪生流域,推进水利工程智能化改造…...
使用kubekey快速搭建k8s集群
项目仓库地址 https://github.com/kubesphere/kubekey/ 支持的Kubernetes Versions https://github.com/kubesphere/kubekey/blob/master/docs/kubernetes-versions.md 安装 选择自己想要下载的版本 https://github.com/kubesphere/kubekey/releases 复制下载链接并下载 示…...
C++——入门基础(上)
目录 一、C参考文档 二、C在工作领域的应用 三、C学习书籍 四、C的第一个程序 五、命名空间 (1)namespace的定义 (2)命名空间的使用 六、C的输入和输出 七、缺省函数 八、函数重载 九、写在最后 一、C参考文档 (1)虽…...
Spring事务失效
类内部访问导致事务不生效原因: 注解Transaction的底层实现是Spring AOP技术,而Spring AOP技术使用的是动态代理。spring事务失效的原因就是动态代理失效的原因: 对于static方法和非public方法,注解Transactional是失效的,因为不…...
Qt QLabel标签制作弹框效果,3s后缓慢自动消失
效果图 初始化说明 void InitStatusTips() {if (NULL statusTips_) {return;}statusTips_->setFixedSize(300, 80);//固定大小statusTips_->move((width() - statusTips_->width()) / 2, height() - 30 - statusTips_->height());//移动位置statusTips_->setA…...
JZ55 二叉树的深度
二叉树的深度_牛客题霸_牛客网 递归代码太简单-一行就可以,可以用二叉树的层序遍历,顺便温习下二叉树层序遍历的写法。 对应leetcode 104题,层序遍历对应leetcode-102自顶向下,leetcode-107自底向上 /* struct TreeNode {int val;struct Tre…...
视频号分销系统搭建教程,源代码+部署上线指南
目录 一、视频号分销是什么? 二、视频号分销系统怎么搭建? 1.系统架构设计 2.部署与上线 3.持续迭代与升级 三、部分代码展示 一、视频号分销是什么? 视频号分销系统是合集了视频号商家的产品,推广达人推广商家的产品可赚取…...
【python】cryptography库学习
【python】cryptography库学习 cryptography学习1-安装2-cryptography学习2.1-fernet的使用2.2-padding填充2.3-Hash2.4-ciphers(对称算法AES为例)2.5-asymmetric(非对称算法RSA为例)函数:generate_private_key类:RSAPrivateKey&a…...
解密!抖音百万粉丝博主三维地图视频都用到了什么GIS数据和技术
引言 在抖音上有许多诸如三维地图科普局、三维地图看世界和三维地图鉴赏等百万粉丝博主靠着三维地图科普城市、景区、人文和地理视频获赞百万,在我们浏览视频时犹如身临其境一般,那么制作这些视频需要什么GIS技术呢?如何利用MapMost技术自己…...
Python知识点:如何使用Kubernetes与Python进行容器编排
Kubernetes 是一个开源的容器编排平台,用于自动化容器化应用的部署、管理和扩展。结合 Python,你可以通过 Kubernetes API 和工具,如 kubectl 和 kubernetes-client 库,来编写和管理容器化应用。以下是如何使用 Kubernetes 和 Pyt…...
Markdown与Word中插入图片的方法及比较
在撰写文档时,无论是技术文档、博客还是学术论文,插入图片都是非常常见的需求。本文将对比两种流行的文本编辑工具——Markdown和Microsoft Word——在插入图片方面的异同点。 Markdown插入图片 如何插入图片 在Markdown中插入图片非常简单࿰…...
Vue3+Vite安装配置tailwindCss
考虑到官网不是很好访问,这里记录一下简单步骤方便小友查阅 1. 安装依赖 npm install -D tailwindcss postcss autoprefixer2. 初始化配置文件 npx tailwindcss init -p3.配置模板路径 /** type {import(tailwindcss).Config} */ export default {content: [&quo…...
大数据学习-Spark基础入门
一、Spark是什么? Stack Overflow的数据可以看出,2015年开始Spark每月的问题提交数量已经超越Hadoop,而2018年Spark Python版本的API PySpark每月的问题提交数量也已超过Hadoop。2019年排名Spark第一,PySpark第二;而十…...
C语言:链表插入
链表的插入分为头插入,中间插入和尾插入。 具体方法如下: #include<stdio.h> #include<stdlib.h>typedef struct node {int s;struct node* pnext; }list;list* addnode(list** pphead, list** ppend, int n) {list* ptemp malloc(sizeof…...
xss 一些例子
目录 XSS 1.Ma Spaghet!编辑 2.Jefff编辑 3.Ugandan Knuckles编辑 4.Ricardo Milos编辑 5.Ah Thats Hawt编辑 6.Ligma编辑 7.Mafia编辑 简单解法就是换一个函数 作者得原意解法 8.Ok, Boomer编辑 XSS 1.Ma Spaghet! 这里接收了一个somebody参数&…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...




