1. 题目链接
LeetCode 35. 搜索插入位置
2. 题目描述
给定一个升序排列的整数数组 nums
和一个目标值 target
,要求:
- 若
target
存在于数组中,返回其索引。 - 若不存在,返回其应插入的位置,使得插入后数组仍保持有序。
示例:
- 输入:
nums = [1,3,5,6], target = 5
→ 输出:2
- 输入:
nums = [1,3,5,6], target = 2
→ 输出:1
3. 示例分析
- 目标存在:
nums = [1,3,5,6], target = 5
,直接返回索引2
。
- 目标不存在:
nums = [1,3,5,6], target = 2
,插入到索引1
,数组变为[1,2,3,5,6]
。
4. 算法思路
二分查找法:
- 初始化指针:
left = 0
,right = nums.size() - 1
。 - 循环缩小范围:
- 计算中间索引
mid = left + (right - left) / 2
(防止整数溢出)。 - 若
nums[mid] < target
,目标在右半区间,调整left = mid + 1
。 - 若
nums[mid] ≥ target
,目标在左半区间或等于当前值,调整right = mid
。
- 计算中间索引
- 终止条件:当
left == right
时,检查nums[left]
与target
的关系:- 若
nums[left] < target
,返回left + 1
。 - 否则,返回
left
。
- 若
5. 边界条件与注意事项
- 空数组处理:用户代码未显式处理空数组,若
nums
为空,访问nums[left]
会导致越界错误。需增加:if (nums.empty()) return 0;
- 目标值大于所有元素:循环结束后
left
指向末尾,nums[left] < target
时返回left + 1
,正确。 - 重复元素:返回第一个匹配或插入位置(符合题意)。
6. 代码实现
class Solution
{
public:int searchInsert(vector<int>& nums, int target) {if (nums.empty()) return 0;int left = 0, right = nums.size() - 1;while(left < right){int mid = left + (right - left) / 2;if(nums[mid] < target) left = mid + 1;else right = mid;}if(nums[left] < target) return left + 1; return left;}
};
暴力枚举法与二分查找法对比图表
对比维度 | 暴力枚举法 | 二分查找法 |
---|---|---|
核心思想 | 遍历数组,找到第一个大于等于 target 的位置。 | 利用有序性,每次将搜索范围缩小一半,定位插入位置。 |
时间复杂度 | O(n)(遍历所有元素)。 | O(log n)(每次缩小一半范围)。 |
空间复杂度 | O(1)(无需额外存储)。 | O(1)(仅需常数变量记录指针)。 |
实现方式 | 单层循环逐个比较元素。 | 循环调整左右指针,计算中间索引。 |
适用场景 | 无序数组、极小数据规模(n ≤ 100)。 | 有序数组、大规模数据(n ≥ 1e6)。 |
优点 | 实现简单,不依赖数组有序性。 | 时间复杂度极低,适合处理大规模数据。 |
缺点 | 数据规模大时性能极差(例如 n=1e6 时需 1e6 次操作)。 | 需显式处理空数组和越界问题,仅适用于有序数组。 |