文章目录
'''
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。
如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
'''
"""
你可以假设数组中无重复元素。
示例 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
"""
方法一: 偏移法
第一想到的是利用下标偏移,与每个元素进行比较,如果相等则返回下标,如果target比当前的数小,那么它将会被插入在当前位置,也就是当前数的下标(因为根据题目,nums是有序的)。
from typing import List
class Solution:
# 类似指针法,从前往后,一个一个对比,时间复杂度O(n)
def searchInsert(self, nums: List[int], target: int) -> int:
index = 0
len_nums = len(nums)
while index < len_nums:
if target == nums[index] or target < nums[index]:
return index
index += 1
return len_nums
方法二:Pythonic
题目中比较关键的一点是“如果目标值不存在于数组中,返回它将会被按顺序插入的位置。”,如果没有这个,通过 nums.index(target)
一行代码就可以了,所以我想到的是,如果nums中没有就把target添加进入后,然后再找。(感觉使用了Python一些内置的方法,都不适合锻炼算法思维)
# 利用Python的in,若没有找到,就放到nums中排序,再返回target下标
def searchInsert1(self, nums: List[int], target: int) -> int:
if target in nums:
return nums.index(target)
nums.append(target)
nums.sort()
return nums.index(target)
方法三:二分法
在有序数组中查找插入元素的位置,显然可以使用二分查找。在循环的过程中,不断排除不需要的解,最后剩下的那个元素就一定是我们想要的。
把需要的目标值留在最后判断,在循环体内不断地把不符合题目要求的子区间排除掉,在退出循环以后,因为只剩下 1 个数没有看到,它要么是目标元素,要么不是目标元素,单独判断即可。
这里正好可以通过下标来迎合题目要求,也无需判断最后一个剩余的原始是否是目标元素,只要剩下一个元素,那么我只要它的下标即可。
# 二分法,看了别人写的思路,然后默写
def searchInsert2(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1
while left <= right: # 想了下,为啥要加=号,通过debug才发现
mid = (left + right) >> 1
mid_var = nums[mid]
if mid_var == target:
return mid
elif mid_var < target:
left = mid + 1
else:
right = mid - 1
return left
当然还有一种方法,就是先把target放进nums中,这样不用排除不符合的元素了,这种情况下使用二分法,会更容易理解和写代码。
我们平常写程序,定位问题其实通常也用的是这个思路。在适当的地方做一些代码输出,在一些地方打断点来debug,逐步缩小范围,最后找到了有 bug 的那一行或几行代码。
这边也复习了一个不常用的小知识点:位运算符
要计算某个整数除以2(或者2的幂次)得到整数,
使用位运算符:mid = (left + right) >> 1
,
而不必这样做:mid = int((left + right) / 2)
。
- << 左移动运算符:运算数的各二进位全部左移若干位,由 << 右边的数字指定了移动的位数,高位丢弃,低位补0。
- >> 右移动运算符:把">>"左边的运算数的各二进位全部右移若干位,>> 右边的数字指定了移动的位数。