搜索插入位置(Search Insert Position)
题目描述
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
要求:
- 请必须使用时间复杂度为 O(log n) 的算法。
示例:
输入: nums = [1,3,5,6], target = 5
输出: 2
输入: nums = [1,3,5,6], target = 2
输出: 1
输入: nums = [1,3,5,6], target = 7
输出: 4
解题思路分析
方法一:二分查找法(推荐)
由于数组已排序且要求时间复杂度为 O(log n),二分查找是最佳选择。
时间复杂度:O(log n)
空间复杂度:O(1)
#include<iostream>
#include<vector>
using namespace std;
int searchInsert(vector<int>& nums, int target) {
// 左闭右闭区间
int left = 0, right = nums.size() - 1;
while(left <= right){ // [left, right] 为合法区间
int mid = left + (right - left) / 2; // 防止溢出
if(nums[mid] == target){
return mid; // 找到目标,直接返回索引
}else if(nums[mid] > target){
right = mid - 1; // 目标在左半区间
}else if(nums[mid] < target){
left = mid + 1; // 目标在右半区间
}
}
// 如果未找到,返回插入位置(即left指针位置)
return left;
}
int main(){
vector<int> nums = {1,3,5,6};
int target = 5;
cout << searchInsert(nums, target) << endl;
return 0;
}
核心思想与关键问题解答
1. 为什么使用二分查找?
思考过程:
- 数组已排序,这是二分查找的前提条件
- 题目要求 O(log n) 时间复杂度,二分查找正好满足
- 即使目标不存在,也需要找到插入位置,二分查找的终止条件能自然提供这个位置
2. 为什么返回 left 指针?
关键原因:
-
当循环结束时,
left > right,此时:left指向第一个大于等于 target 的元素位置right指向最后一个小于 target 的元素位置
-
插入位置应该是第一个大于等于 target 的位置,即
left
示例验证:
-
nums = [1,3,5,6], target = 2
- 最终 left=1, right=0,返回1(正确插入位置)
-
nums = [1,3,5,6], target = 7
- 最终 left=4, right=3,返回4(正确插入位置)
算法流程详解
模拟执行过程(nums = [1,3,5,6], target = 2)
| 步骤 | left | right | mid | nums[mid] | 操作 | 说明 |
|---|---|---|---|---|---|---|
| 初始 | 0 | 3 | - | - | - | 初始化 |
| 1 | 0 | 3 | 1 | 3 | 3>2 → right=0 | 目标在左边 |
| 2 | 0 | 0 | 0 | 1 | 1<2 → left=1 | 目标在右边 |
| 结束 | 1 | 0 | - | - | 返回left=1 | 插入位置为1 |
最终输出:1