高频面试题《二分查找》
在排序数组中查找元素的第一个和最后一个位置题目描述给定一个按照非递减顺序排列的整数数组nums和目标值target找出目标值在数组中的开始位置和结束位置。如果数组中不存在target返回[-1, -1]要求算法的时间复杂度为O(log n)示例输入nums [5, 7, 7, 8, 8, 10], target 8 输出[3, 4]一、为什么使用二分查找题目给出了两个重要条件数组按照非递减顺序排列要求时间复杂度为O(log n)有序数组具备单调性因此可以使用二分查找。普通遍历最坏需要检查数组中的所有元素时间复杂度为O(n)二分查找每次可以排除一半搜索范围时间复杂度为O(log n)例如当数组长度为1024时1024 → 512 → 256 → 128 → ... → 2 → 1最多只需要大约10次查找因为2¹⁰ 1024二、普通二分查找为什么不够普通二分查找只负责寻找任意一个等于target的元素。例如nums [5, 7, 7, 8, 8, 10] target 8普通二分查找可能找到下标3也可能找到下标4。但题目要求返回完整区间[3, 4]因此需要进行两次二分查找寻找第一个大于等于target的位置寻找第一个严格大于target的位置设这两个位置分别为lower_bound upper_bound那么目标值的范围就是[lower_bound, upper_bound - 1]三、左闭右开区间本文采用左闭右开的搜索区间[left, right)其中left对应的位置包含在搜索范围内right对应的位置不包含在搜索范围内初始化left0rightlen(nums)这样[0, len(nums))正好覆盖整个数组。循环条件为whileleftright:当循环结束时left right此时left和right指向最终的边界位置。四、寻找左边界左边界可以定义为数组中第一个大于等于target的位置。也就是寻找第一个满足以下条件的位置nums[i] target情况一nums[mid] target如果nums[mid]target由于数组已经有序mid及其左边的元素都不可能成为答案。因此将左边界更新为leftmid1情况二nums[mid] target如果nums[mid]target说明mid可能是答案但左边还可能存在更靠前的合法位置。因此保留mid继续向左收缩rightmid代码实现deflower_bound(nums,target):left0rightlen(nums)whileleftright:midleft(right-left)//2ifnums[mid]target:leftmid1else:rightmidreturnleft五、手动执行左边界查找对于nums [5, 7, 7, 8, 8, 10] target 8初始状态left 0 right 6第一轮mid 0 (6 - 0) // 2 3 nums[mid] 8因为nums[mid] target执行rightmid更新后left 0 right 3第二轮mid 0 (3 - 0) // 2 1 nums[mid] 7因为nums[mid] target执行leftmid1更新后left 2 right 3第三轮mid 2 (3 - 2) // 2 2 nums[mid] 7执行leftmid1更新后left 3 right 3此时left right不成立循环结束返回3所以第一个大于等于8的位置是下标3。六、寻找右边界为了确定最后一个target的位置可以先寻找第一个严格大于target的位置。也就是寻找第一个满足以下条件的位置nums[i] target如果nums[mid]target说明mid不是第一个大于target的位置需要继续向右寻找leftmid1否则nums[mid]target说明mid可能是答案需要保留mid并继续向左寻找rightmid代码如下defupper_bound(nums,target):left0rightlen(nums)whileleftright:midleft(right-left)//2ifnums[mid]target:leftmid1else:rightmidreturnleftupper_bound返回第一个大于target的位置因此最后一个等于target的位置为upper_bound(nums,target)-1七、两种边界的关键区别寻找左边界时ifnums[mid]target:leftmid1else:rightmid寻找第一个大于目标值的位置时ifnums[mid]target:leftmid1else:rightmid二者的区别只有一个等号lower_boundnums[mid] target upper_boundnums[mid] target当nums[mid] target时寻找左边界继续向左寻找寻找右边界继续向右寻找可以记忆为找左边界相等时向左 找右边界相等时向右。八、如何判断目标值不存在lower_bound找到的是第一个大于等于target的位置但这个位置上的元素不一定等于target。例如nums [5, 7, 7, 8, 8, 10] target 6第一个大于等于6的元素是7其下标为1。因此还需要检查nums[start]target另外如果所有元素都小于targetlower_bound会返回len(nums)例如nums [5, 7, 8] target 10查找结果为start 3 len(nums) 3因此目标值不存在的完整判断是ifstartlen(nums)ornums[start]!target:return[-1,-1]九、为什么必须先判断数组越界下面的判断顺序是安全的ifstartlen(nums)ornums[start]!target:Python 的or具有短路特性。当startlen(nums)为真时Python 不会继续执行nums[start]因此不会发生数组越界。如果把条件反过来ifnums[start]!targetorstartlen(nums):当start len(nums)时程序会先访问不存在的下标从而抛出IndexError: list index out of range十、完整代码classSolution:defsearchRange(self,nums:list[int],target:int)-list[int]:deflower_bound():寻找第一个大于等于 target 的位置。left0rightlen(nums)whileleftright:midleft(right-left)//2ifnums[mid]target:leftmid1else:rightmidreturnleftdefupper_bound():寻找第一个严格大于 target 的位置。left0rightlen(nums)whileleftright:midleft(right-left)//2ifnums[mid]target:leftmid1else:rightmidreturnleft startlower_bound()ifstartlen(nums)ornums[start]!target:return[-1,-1]endupper_bound()-1return[start,end]十一、使用通用函数简化代码也可以将两个二分查找统一为一个通用函数classSolution:defsearchRange(self,nums:list[int],target:int)-list[int]:deflower_bound(value):left0rightlen(nums)whileleftright:midleft(right-left)//2ifnums[mid]value:leftmid1else:rightmidreturnleft startlower_bound(target)ifstartlen(nums)ornums[start]!target:return[-1,-1]endlower_bound(target1)-1return[start,end]这里lower_bound(target)寻找第一个大于等于target的位置。而lower_bound(target 1)对于整数数组而言相当于寻找第一个大于target的位置。需要注意在具有固定整数范围的语言中target 1可能溢出。分别实现lower_bound和upper_bound会更加通用。十二、复杂度分析进行了两次二分查找每次时间复杂度为O(log n)因此总时间复杂度仍然是O(log n)算法只使用了固定数量的变量空间复杂度为O(1)十三、容易犯的错误1. 找到目标值后立即返回ifnums[mid]target:returnmid这样只能找到任意一个目标值不能保证找到左右边界。2. 相等时更新方向错误寻找左边界时相等应该向左收缩rightmid寻找右边界时相等应该继续向右leftmid13. 混用区间定义如果采用左闭右开区间[left, right)就应该保持rightlen(nums)whileleftright:不要随意和闭区间[left, right]的写法混用。4. 返回mid循环结束后应该返回left或者right不能返回mid。因为mid只是最后一次检查的位置当数组为空时mid甚至没有被定义。5. 忘记判断目标值是否存在lower_bound找到的是第一个大于等于目标值的位置不保证该位置的元素一定等于目标值。必须检查startlen(nums)ornums[start]!target十四、二分查找的本质二分查找不只是“在有序数组中寻找某个数”。它更一般的用途是在一个具有单调性的搜索空间中寻找分界点。本题存在两个分界点小于 target | 大于等于 target以及小于等于 target | 大于 target通过两次二分查找确定这两个分界点就能得到目标值的完整区间。最终关系为开始位置 第一个大于等于 target 的位置 结束位置 第一个大于 target 的位置 - 1

相关新闻

A311Y3 vs MT8883:AI边缘计算项目到底该怎么选?

A311Y3 vs MT8883:AI边缘计算项目到底该怎么选?

从NPU、视频、5G到应用场景,聊聊两款端侧AI平台的区别随着AI逐渐从云端走向设备端,AI盒子、机器人、智能终端、工业设备都开始需要更强的本地计算能力。做这类项目时,很多企业会遇到一个问题:A311Y3和MT8883,到底应该怎…

2026/9/30 6:50:04 阅读更多 →
Netty 4.2 使用与构建完全指南:系统要求、JPMS 模块化应用与源码构建实践

Netty 4.2 使用与构建完全指南:系统要求、JPMS 模块化应用与源码构建实践

后端通信网络异步编程 【免费下载链接】netty Netty project - an event-driven asynchronous network application framework 项目地址: https://gitcode.com/gh_mirrors/ne/netty 点击查看 免费下载 导读 Netty 是一个异步事件驱动的网络应用框架,用…

2026/9/30 6:50:04 阅读更多 →
针织 T 恤、运动套装电脑模板机选型与落地指南

针织 T 恤、运动套装电脑模板机选型与落地指南

针织 T 恤、运动套装是服装行业产量最大、标准化最高、季节性最强的品类,广泛用于团体服、活动服、运动套装与休闲针织成衣。针织面料弹力大、极易拉伸,缝制后裁片长短不一,薄料还容易起皱,属于人工缝制极易产生品质缺陷的面料。传…

2026/9/30 6:50:04 阅读更多 →

最新新闻

银河麒麟V10SP1重装怎么保住数据盘?UUID与fstab挂载全流程

银河麒麟V10SP1重装怎么保住数据盘?UUID与fstab挂载全流程

简介:银河麒麟桌面操作系统V10SP1重装教程,重点解决保留“数据盘”不丢失的难题。内容面向具备一定Linux操作基础的技术人员与高级用户,适用于需在系统升级或重装时保护个人数据的场景。文档以PDF形式提供,共1个文件,压…

2026/9/30 7:40:24 阅读更多 →
OSPF与IS-IS双点双向路由引入:路由回馈成因与Route Tag根治方案

OSPF与IS-IS双点双向路由引入:路由回馈成因与Route Tag根治方案

前两天一位做网络集成的朋友给我发消息,说他在实验环境里做了一个OSPF与IS-IS双点双向路由引入的验证,结果发现OSPF域里所有路由器的外部LSA数量几乎翻了一倍。更诡异的是,明明只有两台ASBR,可路由表里同一个前缀却出现了两条外部…

2026/9/30 7:40:24 阅读更多 →
Cocos 彩色旋转 Shader 实战:UV 旋转、HSV 色相与性能优化

Cocos 彩色旋转 Shader 实战:UV 旋转、HSV 色相与性能优化

如果你玩过一些游戏加载页或者角色释放技能时的特效,一定见过那种彩色光带绕着一个中心点不断旋转的画面——红橙黄绿青蓝紫依次切换,像是把彩虹拧成了一根麻花。这种效果在 Cocos 里做其实有好几条路:硬编码贴图序列帧、引擎自带的 Tween 旋…

2026/9/30 7:40:24 阅读更多 →
我的花园世界客服咨询AI流量赋能,我的花园世界科技重塑智能体验新标杆

我的花园世界客服咨询AI流量赋能,我的花园世界科技重塑智能体验新标杆

近期,由湖南改变生物科技有限公司主办、本因内酵未徕品牌协办的“生物科技健康论坛暨AI赋能大健康产业启动会”在长沙市步步高福鹏喜来登酒店隆重举行。活动以“AI流量赋能实体破局——中小企业增长峰会”为主题,汇聚全国大健康行业专家、中小企业负责人、机构代表及…

2026/9/30 7:40:24 阅读更多 →
PHP 实战:网站突然出现大量恶意请求怎么办?从Nginx防护到PHP安全加固完整方案

PHP 实战:网站突然出现大量恶意请求怎么办?从Nginx防护到PHP安全加固完整方案

一、问题背景:网站访问正常,但服务器压力突然升高最近维护一个 PHP 内容管理系统,运维发现:网站没有明显业务增长,但是服务器请求量突然增加。监控:服务器:CPU:90%内存:正…

2026/9/30 7:40:24 阅读更多 →
FinOps落地实战:云成本管理与优化体系搭建指南

FinOps落地实战:云成本管理与优化体系搭建指南

FinOps 这个概念这几年在圈子里出现的频率越来越高,但你要是问十个人它到底是个什么东西,可能九个人的回答都不一样。有人说是云成本管理,有人说是一套财务流程,还有人干脆觉得就是个新造的 Buzzword。以我自己在甲方和乙方都摸爬…

2026/9/30 7:39:24 阅读更多 →

日新闻

Base64 图片头部特征识别:从文件头到格式判断的完整指南

Base64 图片头部特征识别:从文件头到格式判断的完整指南

1. 项目概述:为什么说看懂 base64 图片头部是基本功这几年跟 base64 打交道的机会越来越多,后端接口返回图片、前端渲染验证码、小程序里存小图、还有一些老系统导出报表,动不动就给你一段长到怀疑人生的 base64 字符串。很多人拿到字符串就直…

2026/9/30 0:00:35 阅读更多 →
Java公交站牌广告管理系统:JSP+Servlet+MySQL实战落地指南

Java公交站牌广告管理系统:JSP+Servlet+MySQL实战落地指南

简介:本资源是一份面向Java初学者与课程设计学生的公交站牌广告灯箱管理系统毕业设计文档,聚焦城市公共广告资源信息化管理痛点,提供从需求分析到技术实现的完整方案。文档采用标准学术论文结构,含摘要、英文摘要、目录及五章正文…

2026/9/30 0:00:35 阅读更多 →
用 Redis Lua 构建大模型 API 多租户原子配额治理体系

用 Redis Lua 构建大模型 API 多租户原子配额治理体系

我去年年底接了一个内部 AI 平台的治理需求,背景很直接:公司把 DeepSeek、MiniMax 这类大模型 API 统一封装成内部网关,开放给几个业务团队用。结果第一个月账单出来,额度直接超了 4 倍。仔细查日志,发现原因并不复杂—…

2026/9/30 0:00:35 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/29 8:16:59 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/29 16:41:41 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/9/29 8:24:48 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/29 19:29:29 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/29 5:58:00 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/29 3:55:56 阅读更多 →