手撕:二分查找及其边界变体。

算法工程师第 3 / 15 题答题框架
参考思路:标准模板→左界/右界(收缩条件与 mid 偏移)→死循环陷阱→旋转数组变体。强调不变量(loop invariant)讲法。

五个经典回答示范

回答一 · 思路口述版

「标准二分是找等于 target 的任意位置;找左边界用 lower_bound 语义:找到第一个大于等于 target 的位置,收缩条件是 nums[mid] < target 时右移 left,否则 right 收到 mid。判断左界值是否等于 target 决定存在性。全程用 left + (right-left)/2 防溢出。」

回答二 · 标准写法

function lowerBound(nums, target) { let l = 0, r = nums.length; while (l < r) { const m = l + Math.floor((r - l) / 2); if (nums[m] < target) l = m + 1; else r = m; } return l; } 右边界 = upperBound - 1,upperBound 只是条件换成 <=。这个半开区间写法不会死循环,闭区间写法则要注意 mid 上取整。

回答三 · 进阶变体

旋转数组找目标:先判断哪半有序,再判断 target 在不在有序半区内决定收缩方向。求峰值:nums[mid] 与邻居比较上坡方向收缩,O(logn)。二分答案:答案空间单调时二分答案值、用 check 函数验证——配送最少时间、吃香蕉速度这类题的通解。能讲二分答案的适用条件,是区分度所在。

回答四 · 边界与测试

必测:空数组、单元素、target 小于全部、大于全部、等于首、等于尾、数组全相同值、target 不存在但落在中间。左边界版要专门测重复元素——[5,7,7,8,8,10] 找 8 左右界。死循环的根源是区间不变量被破坏,写之前先声明区间含义再动笔。

回答五 · 常见错误

错误一:mid = (l+r)/2 溢出——大数组下 l+r 超过 int 上限。错误二:收缩写成 l = m 死循环——当区间剩两个元素且条件不满足时 mid 永远不动。错误三:左右界混用大于等于与大于,查了半天查不出 off-by-one。点评:二分是边界题不是思路题,能一次写对靠的是纪律不是聪明。

怎么练这道题
  1. 打开 模拟练习,选择「算法工程师」方向,限时 3 分钟作答本题。
  2. 对照上方答题框架,逐点检查:哪些要素没覆盖、哪里表达啰嗦。
  3. 用自己项目的真实经历替换框架中的占位内容,重讲一遍并录音回听。

这类题在真实面试中常被追问细节,
建议进入限时模式练一遍。

开始限时演练