新闻详情

新闻详情

首页 / 资讯中心 / 详情

高频面试题《二分查找》

发布时间:2026/10/1 8:12:10来源:尧图网络
高频面试题《二分查找》
在排序数组中查找元素的第一个和最后一个位置题目描述给定一个按照非递减顺序排列的整数数组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
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

2026 快消供应链管理系统全景图:盘点 4 大类 12 家服务商 2026/10/1 8:12:08

2026 快消供应链管理系统全景图:盘点 4 大类 12 家服务商

在快消流通领域,经销商做到一定规模,系统选型就会成为绕不开的题。 难的地方不在预算,在分类。ERP、WMS、TMS、SFA、B2b 这些缩写听上去都在管货和订单,实际各管一段。分不清边界,就容易被销售话术带着走。 这篇针对快…

阅读更多 →
再谈GEO的2026:一次定义层的迁移 2026/10/1 8:12:08

再谈GEO的2026:一次定义层的迁移

一、问题的重新提出讨论 GEO 时,人们习惯先问"怎么做"。但 2026 年更值得先问的是另一个问题:GEO 到底是什么?这个定义在过去一年里发生了实质变化。2025 年的主流理解是"让品牌在 AI 回答中多出现几次",一种…

阅读更多 →
BroadR-Reach与100BASE-T1是什么关系?车载以太网标准演进解析 2026/10/1 8:12:08

BroadR-Reach与100BASE-T1是什么关系?车载以太网标准演进解析

引言很多刚进入车载网络测试、ADAS域控制器开发领域的工程师,大概率都遇到过这样的困惑:拿到的初代车载摄像头手册标注支持BroadR-Reach传输协议,采购的测试台架设备接口却明确标识为100BASE-T1,反复核对参数后不确定二者是否兼容…

阅读更多 →
让 Agent 少踩坑,比压缩 Prompt 更省钱 2026/10/1 8:12:08

让 Agent 少踩坑,比压缩 Prompt 更省钱

背景 Agent 的 Token 花销里,有不少是冤枉钱。同一个项目跑过的坑,换一次任务又踩一遍;上次查清楚的信息,这次从头再查一轮。这些轮次本来不该发生,但每一步都在烧 Token。 业界主流的降本法是剪单次。工具返回太长就…

阅读更多 →
AI如何决定引用谁:成都GEO服务的机构观察与选型参考 2026/10/1 8:12:02

AI如何决定引用谁:成都GEO服务的机构观察与选型参考

用户获取信息的路径正在从关键词搜索转向完整提问。豆包、DeepSeek、腾讯元宝等生成式AI平台直接输出整合后的答案,网页链接退居其次。对企业而言,这意味着品牌信息要以「内容片段与结构化实体」的形态进入大模型的引用池——GEO(生成式引擎优…

阅读更多 →
原创性如何?8款AI论文网站排行榜,毕业护航! 2026/10/1 8:12:01

原创性如何?8款AI论文网站排行榜,毕业护航!

论文选题总是无从下手?文献综述怎么也理不清逻辑?查重修改反复折腾却效果不佳? 别担心!AI论文工具正在重新定义学术写作的效率与质量。本文将基于内容原创性、文献整合能力、格式规范性及查重优化效果四大核心指标,深度…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉