互联网行业的小白,写博客的目的是为了记录自己的学习过程、对自己学习中所犯的错误做一个总结。由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!
题目描述
题目传送门:搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
示例 4:
输入: [1,3,5,6], 0
输出: 0
题解
要在数组中插入目标值,只有一下四种情况:
- 目标值在数组所有元素之前
- 目标值等于数组中某一个元素
- 目标值插入数组中的位置
- 目标值在数组所有元素之后
暴力实现 |
直接遍历数组即可
AC代码
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
for index, num in enumerate(nums):
if target <= num:
return index
return len(nums)
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
二分查找 |
首先要注意:二分的条件是数组有序,本题满足条件
同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的。
既然暴力解法的时间复杂度是 O ( n ) O(n) O(n),就要尝试一下使用二分查找法。
在下图中举例说明了二分查找的基本过程,注意返回的终止条件
二分查找涉及的很多的边界条件,逻辑比较简单,但是稍不注意,就会弄错。
while(left < right)
与while(left <= right)
采用哪种写法?right = middle
与right = middle - 1
又采用哪种写法?
这里弄不清楚主要是因为对区间的定义没有想清楚,这就是不变量。
要在二分查找的过程中,保持不变量,这也就是循环不变量
第一种写法:定义 target 是在一个在左闭右闭的区间里,即[left, right]
AC代码
注意为什么要写while(left <= right)和right = middle - 1
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums) - 1 # 定义target在左闭右闭的区间里,[left, right]
while(left <= right): # 当left==right,区间[left, right]依然有效
mid = left + (right - left) // 2 # 为了防止left + right溢出,和(left + right)/2效果一样
if target == nums[mid]:
return mid
elif target < nums[mid]:
right = mid - 1 # target 在左区间,所以[left, middle - 1]
else:
left = mid + 1 # target 在右区间,所以[middle + 1, right]
"""分别处理如下四种情况
目标值在数组所有元素之前 [0, -1]
目标值等于数组中某一个元素 return mid;
目标值插入数组中的位置 [left, right] 此时 return right + 1
目标值在数组所有元素之后的情况 [left, right] 此时 return right + 1
"""
return right + 1
时间复杂度:
O
(
l
o
g
n
)
O(logn)
O(logn)
空间复杂度:
O
(
1
)
O(1)
O(1)
第二种写法
AC代码
注意为什么要写while(left < right)和right = middle
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums) # 定义target在左闭右开的区间里,[left, right)
while(left < right): # 因为left == right的时候,在[left, right)是无效的空间
mid = left + (right - left) // 2 # 为了防止left + right溢出,和(left + right)/2效果一样
if target == nums[mid]:
return mid # 数组中找到目标值的情况,直接返回下标
elif target < nums[mid]:
right = mid # 在左区间,在[left, middle)中
else:
left = mid + 1 # 在右区间,在 [middle+1, right)中
"""分别处理如下四种情况
目标值在数组所有元素之前 [0,0)
目标值等于数组中某一个元素 return mid;
目标值插入数组中的位置 [left, right) 此时 return right
目标值在数组所有元素之后的情况 [left, right) 此时 return right
"""
return right
时间复杂度:
O
(
l
o
g
n
)
O(logn)
O(logn)
空间复杂度:
O
(
1
)
O(1)
O(1)
码字不易,您的
支持
就是我坚持
下去的动力,一起加油哦。