给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(logn) 的算法。
示例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
示例4:
输入: nums = [1,3,5,6], target = 0
输出: 0
示例5:
输入: nums = [1], target = 0
输出: 0
1.暴力解法
暴力解法与题意不符,因为时间复杂度为 O(n),但是作为初学者来说还是要以此为基础再进行进一步的拓展,思想就是每一个nums[i]与target进行对比。
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
lens = len(nums)
i = 0
for i in range(lens):
if nums[i] < target:
continue
else:
return i
return i + 1
2.二分查找法
查找有序的整数都可以用二分查找来解决,极大地减少时间复杂度,也就是题目要求的正确解法。
算法思想:
(1)设定数组左侧下标为left,右侧下标为right,中间下标为mid;
(2)比较target与nums[mid]的大小,若target<=nums[mid],则right左移;若target>nums[mid],则left右移。
(3)若查找没有相等的值,则返回left,即为插入位置。
注:
(1)每次跳出循环时left=right+1。
(2)当找到目标值时,left=mid,则不需要插入;当未找到目标值时,left=mid+1=right+1,所以left为插入位置。
添加这个注释看似有点画蛇添足,但是真正自己动手画图之时才明白这两条注释真正含义。
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
lens = len(nums)
left = 0
right = lens - 1
ans = lens
while left <= right:
mid = (right + left) // 2 #/得到的是浮点数除法,//才能得到整数除法
if target <= nums[mid]:
ans = mid
right = mid -1
else:
left = mid + 1
return ans
番外
以下语句与mid = (right + left) // 2相同。右移运算符>>运算结果正好能对应一个整数的二分之一值,这就正好能代替数学上的除2运算,但是比除2运算要快。
mid = (right + left) >> 1