搜索插入位置
755 字
4 分钟
搜索插入位置
题目链接:35. 搜索插入位置 - 力扣(LeetCode)
- 难度:简单
- 标签:数组、二分查找
题目描述
Note
原题说明: 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
要求:必须使用时间复杂度为 的算法。
示例
- 输入:
nums = [1,3,5,6], target = 5-> 输出:2 - 输入:
nums = [1,3,5,6], target = 2-> 输出:1 - 输入:
nums = [1,3,5,6], target = 7-> 输出:4
方案一:线性扫描(初步尝试)
核心思路:
遍历数组,找到第一个大于或等于 target 的元素下标。如果遍历完都没找到,说明 target 应该插在数组末尾。
源码实现
class Solution {public: int searchInsert(vector<int>& nums, int target) { for (int i = 0; i < nums.size(); ++i) { if (nums[i] >= target) { return i; } } return nums.size(); }};复杂度分析
- 时间复杂度:。在最坏情况下,我们需要遍历整个数组。
- 空间复杂度:。
方案二:二分查找(进阶解法)
核心思路: 利用数组已排序的特性,采用“折半查找”的思想。通过不断缩小目标值所在的区间,将搜索时间从线性降低到对数级别。
源码实现(左闭右开区间)
class Solution {public: int searchInsert(vector<int>& nums, int target) { int left = 0, right = nums.size(); // 定义 [left, right)
while (left < right) { // 当闭区间不为空 int mid = left + (right - left) / 2; // 防止溢出的中点写法
if (nums[mid] < target) { left = mid + 1; // 目标在右侧,缩小左边界 } else { right = mid; // 目标在左侧或就是 mid,缩小右边界 } } return left; // 最终 left == right,即为插入位置 }};复杂度分析
- 时间复杂度:。每次比较都会使搜索区间缩小一半。
- 空间复杂度:。
深度解析:为什么 right = nums.size()?
在二分查找中,边界处理(Boundary Conditions)是公认的难点。
- 左闭右开
[left, right):初值设为right = nums.size()。- 循环条件是
while (left < right)。 - 当
target大于数组所有元素时,left会一直增加直到等于nums.size(),最终返回的值正好是末尾插入位置。
- 循环条件是
- 防止溢出:使用
left + (right - left) / 2而非(left + right) / 2,是为了在大数运算时防止left + right导致整型溢出。
总结
- 有序即二分:看到“有序数组”和“查找”这两个关键词,第一时间要联想到二分查找。
- 复杂度达标:题目明确要求 ,因此线性扫描虽然能通过(在数据量小时),但在面试中不符合要求。
Tip
二分查找不仅仅是“找值”,它更是一种高效缩减搜索范围的范式。掌握了“左闭右开”或“左闭右闭”的固定模版,可以极大减少低级 Bug 的产生!
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
最后更新于 2025-10-11,距今已过 200 天
部分内容可能已过时
相关文章 智能推荐
1
合并两个有序数组
算法 力扣第88题:合并两个有序数组。从正向合并的繁琐到逆向双指针的极简之美,实现 $O(m+n)$ 的高效原地合并。
2
x 的平方根
算法 力扣第69题:实现 sqrt(x)。深入理解二分查找在数值逼近中的应用,以及避免溢出的数学处理技巧。
3
加一
算法 力扣第66题:加一。处理大整数数组的进位逻辑,从逐位检查到首位插入的技巧分析。
4
移除元素
算法 力扣第27题:原地移除数组中所有等于 val 的元素。深入理解快慢指针在乱序数组中的灵活应用。
5
删除有序数组中的重复项
算法 力扣第26题:原地删除有序数组中的重复项。从基础的标记替换,到快慢指针(Two Pointers)的高效演进。
随机文章 随机推荐