【LeetCode 刷题笔记】35. 搜索插入位置 | 二分查找经典入门题


一、题目描述

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

示例 1:

复制代码
输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:

复制代码
输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:

复制代码
输入: nums = [1,3,5,6], target = 7
输出: 4

二、解题思路

  • 题目明确要求时间复杂度为 O(log n),因此暴力遍历(O(n))不符合要求,必须使用二分查找
  • 核心需求拆解:
    1. 若数组中存在目标值,直接返回其索引;
    2. 若目标值不存在,返回按升序插入的位置(本质是寻找数组中第一个大于目标值的元素的索引)。
  • 二分查找核心逻辑:通过不断缩小查找区间,每次排除一半元素,最终定位目标值或确定插入位置。

三、代码实现(Java)

解法1:

复制代码
class Solution {
    public int searchInsert(int[] nums, int target) {
        // 边界处理:数组为null的鲁棒性判断
        if(nums == null){
            return -1;
        }
        // 初始化二分查找区间(闭区间 [low, high])
        int low = 0;
        int high = nums.length - 1;
        int mid = 0;
        // 二分查找循环:low <= high 保证所有元素都被遍历
        while(low <= high){
            // 计算中间位置,避免 low + high 直接相加导致int溢出
            mid = low + (high - low) / 2;
            if(nums[mid] == target){
                // 找到目标值,直接返回索引
                return mid;
            }
            else if(nums[mid] < target){
                // 目标值更大,需向右半部分查找,更新左边界
                low = mid + 1;
            }
            else{
                // 目标值更小,需向左半部分查找,更新右边界
                high = mid - 1;
            }
        }
        // 退出循环时,low 即为目标值的插入位置
        return low;
    }
}

也可以用 【LeetCode 刷题笔记】34. 在排序数组中查找元素的第一个和最后一个位置 | 二分查找经典刷题题解这篇文章的思路,本质也还是二分查找。
解法2:代码如下:

复制代码
class Solution {
    public int mySqrt(int x) {
        int l = 0, r = x, ans = -1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if ((long) mid * mid <= x) {
                ans = mid;
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        return ans;
    }
}

四、核心笔记&易错点解析

1. 边界情况处理:空数组/空输入

  • nums == null 时,返回-1(题目默认nums为有效排序数组,添加此判断可提升代码鲁棒性)。

  • nums.length == 0 时,high = nums.length - 1 = -1,此时循环条件 low <= high0 <= -1)不成立,直接退出循环,返回 low = 0,正好对应空数组的插入位置为0,符合题目要求。

2. 为什么循环退出后直接返回 low

很多同学会疑惑:循环结束时 low > high,此时low为什么一定是正确的插入位置?我们可以结合循环的最后一步(low == high时)分析:

low == high 时,mid = low = high,此时分三种情况:

  1. nums[mid] == target:已在循环内直接return mid,不会走到退出循环的步骤;

  2. nums[mid] < target :目标值比当前mid位置的元素大,插入位置应为 mid + 1。循环内会执行 low = mid + 1,此时 low > high,退出循环,low 正好等于 mid + 1,即正确插入位置;

  3. nums[mid] > target :目标值比当前mid位置的元素小,插入位置应为当前的mid(即low)。循环内会执行 high = mid - 1,此时 low > high,退出循环,low 仍为原来的mid值,即正确插入位置。

因此,无论哪种情况,循环退出后low一定是目标值的正确插入位置。

3. 二分查找细节优化

  • mid = low + (high - low) / 2:相比直接写 mid = (low + high) / 2,这种写法可避免 low + high 超过int最大值导致溢出,是二分查找的标准写法。

  • 循环条件 low <= high:这是闭区间二分查找的标准条件,保证数组所有元素都被遍历到,不会漏掉边界情况。


五、复杂度分析

  • 时间复杂度O(log n),每次循环将查找区间缩小一半,最多循环log₂n次,完全符合题目要求。

  • 空间复杂度O(1),仅使用了常数级别的额外空间。


六、总结

  • 这道题的核心是利用二分查找实现O(log n)的时间复杂度,关键在于理解循环退出后low的含义。

  • 闭区间二分查找的模板需要牢记,尤其是边界条件和mid的计算方式,避免溢出和死循环。

  • 这类"寻找插入位置"的问题,本质上是寻找数组中第一个大于等于目标值的元素的索引,用二分查找可以高效解决。

相关推荐
北域码匠7 小时前
高通滤波算法深度解析(High-Pass Filter)
stm32·算法·c#·数字信号处理·嵌入式开发·滤波算法·高通滤波
指掀涛澜天下惊7 小时前
强化学习进阶篇八 策略梯度算法
深度学习·学习·算法·强化学习
乌萨奇也要立志学C++7 小时前
【洛谷】kmp算法
开发语言·算法
禹凕8 小时前
Dijkstra算法详解与应用
python·算法
YaraMemo8 小时前
元启发式算法框架
人工智能·算法·5g·信息与通信·启发式算法·信号处理
weixin_307779139 小时前
一维无粘 Burgers 方程的激波形成问题:MacCormack 格式求解
c++·算法·matlab
HugoStudio_SWAN9 小时前
洛谷 B4500 / B4449 / B3843 凯撒密码、密码强度与密码合规——加密与安全的三道门
c++·学习·程序人生·算法·安全
枫叶林FYL10 小时前
【群体智能集群控制工程实践】第3章 一致性协同算法
算法
禹凕10 小时前
滑动窗口算法实战指南
python·算法
DisonTangor11 小时前
【腾讯混元雪耻归来】 Hy4 preview:770B 参数 MoE 旗舰模型,1M 上下文全面开源
人工智能·算法·开源·aigc·腾讯云·腾讯云ai代码助手