题目
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 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
提示:
1 <= nums.length <= 104-104 <= nums[i] <= 104nums为 无重复元素 的 升序 排列数组
解题思路🙋🏻 ♀️
使用数组 nums = [1, 3, 5, 7, 9, 11] 和目标值 target = 8 进行演示 searchInsert 函数的执行过程。
-
首先,我们初始化左边界
L = 0和右边界R = nums.count - 1 = 5。 -
然后,我们开始
while循环,条件为L <= R。
第一次循环:
-
我们计算
mid的值:mid = L + (R - L) / 2 = 0 + (5 - 0) / 2 = 2。因此,mid的值为2。 -
我们发现
nums[mid] = 5小于目标值8,所以我们将L更新为mid + 1 = 3。
数组:[1,3,5,7,9,11]
L M R
索引: 0 1 2 3 4 5
第二次循环:
-
我们重新计算
mid的值:mid = L + (R - L) / 2 = 3 + (5 - 3) / 2 = 4。因此,mid的值为4。 -
我们发现
nums[mid] = 9大于目标值8,所以我们将R更新为mid - 1 = 3。
数组:[1,3,5,7,9,11]
LMR
索引: 0 1 2 3 4 5
第三次循环:
-
我们重新计算
mid的值:mid = L + (R - L) / 2 = 3 + (3 - 3) / 2 = 3。因此,mid的值为3。 -
我们发现
nums[mid] = 7小于目标值8,所以我们将L更新为mid + 1 = 4。
数组:[1,3,5,7,9,11]
L R
索引: 0 1 2 3 4 5
现在,我们的左边界 L = 4,右边界 R = 3,不满足 while 循环的条件 L <= R,所以循环结束。
最后,我们返回 L 的值 4,表示目标值 8 应该插入的位置。
边界思考🤔
代码
第一版.
class Solution {
func searchInsert(_ nums: [Int], _ target: Int) -> Int {
// 初始化左右边界
var left = 0
var right = nums.count - 1
// 当左边界小于右边界时,进行二分查找
while left < right {
// 计算中间值
let mid = left + (right - left) / 2
// 如果中间值大于目标值,更新右边界为中间值减一
if nums[mid] > target {
right = mid - 1
// 如果中间值小于目标值,更新左边界为中间值加一
} else if nums[mid] < target {
left = mid + 1
// 如果中间值等于目标值,直接返回中间值索引
} else {
return mid
}
}
// 二分查找结束,如果左边界对应的值大于目标值,返回左边界
if nums[left] > target {
return left
// 如果左边界对应的值小于目标值,返回左边界加一
} else if nums[left] < target {
return left + 1
// 如果左边界对应的值等于目标值,返回左边界
} else {
return left
}
}
}
第二版本
class Solution {
func searchInsert(_ nums: [Int], _ target: Int) -> Int {
var left = 0
var right = nums.count - 1
while left <= right {
let mid = left + (right - left) / 2
if nums[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}
return left
}
}
注意
区别在这一行
while left <= right {
while left < right {
像 shipWithinDays 中的船的最低运载能力, (10 的题目))。我们希望找到的是满足某种条件的最小值(或最大值)。在这种情况下,我们通常使用 left < right 作为循环条件。
在循环结束时,left 和 right 将指向我们要找的值。在 shipWithinDays 的问题中,left 和 right 最终会指向满足所有货物在给定天数内运送完成的最小运载能力。
选择 < 还是 <= 主要取决于我们的目标。如果我们正在寻找一个特定的值,我们通常使用 <=。如果我们正在寻找一个满足特定条件的最小值或最大值,我们通常使用 <。
时空复杂度分析
O(logn)