35.搜索插入位置

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

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

示例 1:

1
2
输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:

1
2
输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:

1
2
输入: nums = [1,3,5,6], target = 7
输出: 4

示例 4:

1
2
输入: nums = [1,3,5,6], target = 0
输出: 0

示例 5:

1
2
输入: nums = [1], target = 0
输出: 0

解题思路

这是一道经典的二分查找题目,考察对二分查找的理解和应用。

核心思想

  • 使用二分查找在有序数组中查找目标值
  • 如果找到目标值,返回其索引
  • 如果没找到,返回应该插入的位置

方法一:标准二分查找(推荐)

时间复杂度 O(log n)、空间复杂度 O(1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var searchInsert = function(nums, target) {
let left = 0;
let right = nums.length - 1;

while (left <= right) {
const mid = Math.floor((left + right) / 2);

if (nums[mid] === target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}

// 如果没找到,left就是应该插入的位置
return left;
};

方法二:优化版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var searchInsert = function(nums, target) {
let left = 0;
let right = nums.length;

while (left < right) {
const mid = Math.floor((left + right) / 2);

if (nums[mid] >= target) {
right = mid;
} else {
left = mid + 1;
}
}

return left;
};

方法三:使用内置函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var searchInsert = function(nums, target) {
// 如果目标值大于数组最大值,插入到末尾
if (target > nums[nums.length - 1]) {
return nums.length;
}

// 使用indexOf查找目标值
const index = nums.indexOf(target);
if (index !== -1) {
return index;
}

// 找到第一个大于target的位置
for (let i = 0; i < nums.length; i++) {
if (nums[i] > target) {
return i;
}
}

return nums.length;
};

方法四:递归二分查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var searchInsert = function(nums, target) {
return binarySearch(nums, target, 0, nums.length - 1);
};

function binarySearch(nums, target, left, right) {
if (left > right) {
return left;
}

const mid = Math.floor((left + right) / 2);

if (nums[mid] === target) {
return mid;
} else if (nums[mid] < target) {
return binarySearch(nums, target, mid + 1, right);
} else {
return binarySearch(nums, target, left, mid - 1);
}
}

解题要点

  1. 二分查找:利用数组有序的特性,使用二分查找
  2. 插入位置:如果没找到目标值,left指针指向的位置就是应该插入的位置
  3. 边界处理
    • 目标值小于数组最小值:插入到位置0
    • 目标值大于数组最大值:插入到数组末尾
    • 目标值在数组范围内:插入到第一个大于它的位置

面试要点

  • 高频考点:这道题是面试中的高频题目
  • 二分查找:考察对二分查找的理解和应用
  • 时间复杂度:要求O(log n)的时间复杂度
  • 边界处理:注意各种边界情况的处理

相关题目

扩展思考

  1. 为什么left是插入位置?

    • 当left > right时,说明没找到目标值
    • left指向的是第一个大于target的位置
    • 这就是target应该插入的位置
  2. 时间复杂度分析

    • 二分查找:O(log n)
    • 线性查找:O(n)(不符合要求)
  3. 边界情况

    • 空数组:返回0
    • 只有一个元素:根据大小关系返回0或1
    • 目标值等于数组元素:返回该元素的索引
  4. 二分查找的变种

    • 查找第一个等于target的位置
    • 查找最后一个等于target的位置
    • 查找第一个大于target的位置
  5. 实际应用

    • 数据库中的索引查找
    • 游戏中的排行榜插入
    • 算法中的插入排序优化

最后更新: 2021-09-12