前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库二分查找 插入位置
算法算法搜索与排序

二分查找失败时如何返回目标值应插入的位置?

查找失败时返回插入点,只需在二分查找中记录左指针,循环结束它指向第一个不小于目标的索引,即插入位置。

前端进阶之旅 · 一题精讲更新于 2026.09.05
算法#搜索与排序
先看核心答案读代码示例
理解线索

插入点的本质

  1. 下界定义第一个不小于目标的索引,即 lower_bound
  2. 不变量left 左边均小于目标,right 右边均不小于
  3. 终止条件left 与 right 重合,位置就是答案

空数组返回0,数组全小于目标时返回长度

核心回答

先记住这个答案

使用左闭右开写法,令 left=0, right=n,循环不变量是 left 左侧元素均小于 target,right 右侧元素均不小于 target。每次比较中位数,若 nums[mid] < target 则 left=mid+1,否则 right=mid。终止于 left==right,该位置就是下界,插入 target 后保持有序。目标存在时也返回第一个相等索引,目标不存在时返回正确插入位。

  • 插入位置是第一个不小于目标的索引
  • 左闭右开写法免去存在性判断分支
  • 循环结束的 left 即 lower_bound 结果

为何循环结束时 left 落在插入点

二分查找每次依据与中位数的比较收缩候选区间。采用左闭右开区间 [left, right) 表示包含下界在内的区间,不变量是 left 左端元素全小于 target,right 右端元素全不小于 target。收缩区间时这一性质被保留。

循环条件 left < right 持续,取中点 mid。若 nums[mid] < target,则 mid 及其左边都小于目标,可令 left=mid+1 同时不破坏不变量;反之 right=mid 排除右侧不含下界的部分。最终 left 与 right 相遇,即第一个使得谓词不小于 target 成立的位置,这正是插入点。

标准 lower_bound 返回插入位置JavaScript
function searchInsert(nums, target) {
    let left = 0, right = nums.length;
    while (left < right) {
        const mid = left + Math.floor((right - left) / 2);
        if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }
    return left;
}

console.log(searchInsert([1,3,5,6],5)); // 2
console.log(searchInsert([1,3,5,6],2)); // 1
console.log(searchInsert([1,3,5,6],7)); // 4
console.log(searchInsert([1,3,5,6],0)); // 0
console.log(searchInsert([],5));        // 0
查看输出与解释
2
1
4
0
0

时间复杂度 O(log n),空间 O(1)。输入包含命中、未命中、大于所有、小于所有、空数组五类,返回值均正确代表插入后保持升序的索引。

应用:LeetCode 35 搜索插入位置

题目要求给定升序数组与目标值,返回目标值存在时的下标或应插入的位置。例如 nums=[1,3,5,6],target=2 返回 1,target=7 返回 4。若用朴素二分找到目标才停止,需额外补判断;而用 lower_bound 直接得结果,代码简洁统一。

该解法等价于标准库的 lower_bound。Java 的 Arrays.binarySearch 返回负数时可用 "-(result)-1" 的公式推导插入点,但自己实现用此模式更直观。面对重复值它返回最左侧匹配位置,将新元素插在此处仍保持有序,满足大多数场景的稳定性需求。

边界条件与失效风险

数组为空时,循环不执行,left=0 返回 0,正确。目标小于首元素时,每次比较都落入 else 分支,right 持续缩小到 0,返回 0;目标大于所有元素时,每次触发 left=mid+1,最终 left=n 返回数组长度,即追加到末尾。这两类无需特判。

若写成左闭右闭解法,需控制 right 为 n-1,结束时可能返回 left 也要检查越界,容易出错。左闭右开形成 right=n 则避免该问题。当含重复值且要求插入到最后一个相等元素之后,应改用 upper_bound(第一个大于目标的位置),否则 lower_bound 插在相等项之前。

回答前,多想一步

容易答错的地方

失败时返回 mid 即可
这是常见错误:二分查找找不到时 mid 可能落在任意位置,只有维护下界不变量才能保证 left 是精确插入点。直接返回 mid 往往结果错误,例如 nums=[1,3], target=2 时 mid=0,但正确插入点是 1。
循环结束后需要检查 left 是否越界
使用左闭右开区间时 left 范围本就是 0 到 n,返回它无需额外检查。很多左闭右闭教程结束后需要判断 left==n 等,但左闭右开写法将越界情况自然映射为返回值,省去分支。
试着用自己的话回答

面试官还会怎么问?

如果目标存在且重复,应该返回哪个索引作为插入点?

若需把新值插入到相等项之前,用 lower_bound 返回第一次出现的位置;若插入到相等项之后,用 upper_bound 返回第一个大于目标的索引。两种结果都不破坏升序,决策取决于业务上的稳定性需求。

如何用二分查找同时判断目标是否存在并返回正确插入位?

先调用 lower_bound 得到 pos,再比较 pos 是否小于数组长度且 nums[pos] == target。若相等则存在,否则不存在且 pos 就是插入位置。这样只花费一次 O(log n) 查询,无需额外状态。

计算中点时用 left + Math.floor((right-left)/2) 有什么好处?

避免 left+right 直接相加可能引起的整数溢出,在其他强类型语言中尤其关键。同时它使 mid 偏向左侧,配合 while(left<right) 可防止区间无变化导致死循环。

从一道题,走向一组知识

把知识连起来

搜索与排序

写二分查找时用左闭右闭和左闭右开区间有什么本质区别?

插入位置实现依赖区间不变量,该文章解释左闭右闭与左闭右开写法的本质差异,帮助理解终止时 left 为何正确。

搜索与排序

二分查找如何找到目标值的第一个出现位置?

lower_bound 即查找第一个不小于目标的索引,与查找第一个出现位置共用同一核心,可对比处理重复元素的异同。

参考资料

  • Binary search¶

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 为何循环结束时 left 落在插入点
  3. 应用:LeetCode 35 搜索插入位置
  4. 边界条件与失效风险
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑