LeetCode35. 搜索插入位置:二分查找的基础与细节

今天我们来拆解 LeetCode 热题 100 中的第 35 题「搜索插入位置」,这道题是二分查找的入门经典,也是很多算法面试的高频考点,非常适合用来理解二分查找的核心逻辑与边界处理。


题目描述

给定一个无重复元素的升序数组 nums 和一个目标值 target,要求:

  1. target 存在于数组中,返回其索引;
  2. 若不存在,返回它按升序插入数组后的位置索引;
  3. 必须实现时间复杂度为 O (log n) 的算法。

示例:

  • 输入:nums = [1,3,5,6], target = 5 → 输出:2(找到目标值,直接返回索引)
  • 输入:nums = [1,3,5,6], target = 2 → 输出:1(插入到元素 3 的前面)
  • 输入:nums = [1,3,5,6], target = 7 → 输出:4(插入到数组末尾)

解题思路:二分查找的核心逻辑

这道题的本质是在有序数组中找到第一个大于等于 target 的位置 ,也就是算法中常说的 lower_bound 问题。二分查找的优势在于,每次可以将问题规模减半,将时间复杂度从暴力遍历的 O (n) 优化到 O (log n)。

关键细节

  1. 指针初始化 :左指针 left 指向数组开头,右指针 right 指向数组末尾,形成闭区间 [left, right]

  2. 中间位置计算 :使用 left + Math.floor((right - left) / 2) 而非 (left + right) / 2,避免数组长度过大时出现数值溢出问题。

  3. 区间收缩逻辑

    • nums[mid] == target:直接返回 mid,找到目标值;
    • nums[mid] < target:目标值在右侧区间,更新 left = mid + 1
    • nums[mid] > target:目标值在左侧区间,更新 right = mid - 1
  4. 循环结束处理 :当 left > right 时循环结束,此时 left 就是目标值的插入位置,因为它指向第一个大于 target 的元素索引。


代码实现(JavaScript)

javascript

运行

ini 复制代码
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var searchInsert = function(nums, target) {
    let left = 0;
    let right = nums.length - 1;

    while (left <= right) {
        // 防止溢出,等价于 Math.floor((left + right) / 2)
        const mid = Math.floor(left + (right - left) / 2);
        if (nums[mid] === target) {
            // 找到目标值,直接返回索引
            return mid;
        } else if (nums[mid] < target) {
            // 目标值更大,去右边找
            left = mid + 1;
        } else {
            // 目标值更小,去左边找
            right = mid - 1;
        }
    }

    // 没找到,left 就是插入位置
    return left;
};

复杂度分析

  • 时间复杂度:O (log n),每次循环将问题规模减半,最多循环 log₂n 次;
  • 空间复杂度:O (1),仅使用常数级别的额外空间。

常见误区与优化

很多同学写这道题时,容易在循环条件和指针更新上出错:

  1. 错误地使用 left < right 作为循环条件,导致边界处理逻辑复杂;
  2. 中间位置直接写 (left + right) / 2,忽略了数值溢出的风险;
  3. 循环结束后不知道该返回 left 还是 right,这也是二分查找的经典易错点。

其实只要理解了 "循环结束时 left 一定指向第一个大于等于 target 的位置",这个问题就迎刃而解了。


这道题虽然简单,但二分查找的思想在很多算法题中都有延伸,比如查找重复元素的左右边界、旋转有序数组的最小值等。掌握好这道题,能帮你打下扎实的二分查找基础。

相关推荐
吃好睡好便好12 小时前
查找函数的使用
学习·算法·matlab·生活·查找函数
学习星球12 小时前
单调栈——从“找下一个更大的“到柱状图中的最大矩形
数据库·c++·算法·leetcode·xcode
可乐鸡翅yeah_13 小时前
hls.js 内存泄漏实战排查,直播 M3U8 长时间播放异常定位方案
开发语言·javascript·python·django·ecmascript·m3u8·m3u8在线
可乐鸡翅yeah_13 小时前
第三方接口对接 M3U8 流媒体排坑实战,解决外部服务商流兼容难题
前端·javascript·python·django·html·m3u8·m3u8在线
默_笙13 小时前
🏠 「LLM Notes」:我用 Next.js + Redis 给自己造了个笔记博客
前端·javascript
靠沿14 小时前
贪心算法专题(二)
算法·贪心算法
猎头南楼14 小时前
具身智能模型部署方向的能力要求与技术栈梳理
人工智能·深度学习·算法
ruanCat15 小时前
Prettier 明明执行成功,Markdown 为什么还是没变?一次插件误诊复盘
前端·javascript·node.js
软件开发技术深度爱好者15 小时前
在线学习实践 TypeScript 的官方Playground(演练场)使用介绍
javascript·学习·typescript
啥都想学点的研究生15 小时前
一篇文章讲清楚:线性回归问题的求解——正规方程法
算法·机器学习·线性回归