目录
704. 二分查找
题目链接:. - 力扣(LeetCode)
文章讲解:代码随想录
解题卡点:循环的条件,即while里写什么
二分查找前提:①有序数组;②无重复元素。
双指针法:左右指针向数组中心移动,直到找到目标元素。
解题卡点:当循环到最后时,左右指针指向相同的元素索引,此时左右指针索引相同。即当右指针小于左指针时跳出循环。
Tips:求中间索引时,为防止(a+b)/2的分子溢出,使用a+(b-a)/2替代。也可使用a+((b-a)>>1)替代。对于二进制的正数来说,右移x位相当于除以2的x次方。
总结:二分查找难点在于如何循环,控制边界条件。这里我将左右指针代表为元素的索引,求出的mid也为索引,nums[索引]一定可以取到。当nums[mid]≠target时,mid索引对应的元素已经判断过,故指针移动时不用把mid再包含进去。当指针移动到最后,right=left时,因为是索引所以nums[mid]依然可以取到,代表着right与left指向同一个元素,只有当right<left时才无法继续,故循环条件为right≥left。
class Solution:
def search(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums)-1
while right >= left: # 当两者相等时,索引依然有效
mid = left+(right-left)//2 # 防加法溢出
if nums[mid] > target:
right = mid-1 # mid索引对应的元素被上一行判断了,right应该比mid再小一位
elif nums[mid] < target:
left = mid+1 # left应该比mid再大一位
else:
return mid
return -1 # 跳出循环时代表目标值不在数组中,返回-1
# 时间复杂度 O(log n)
# 空间复杂度 O(1)
双指针法:快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组;慢指针:指向更新新数组下标的位置。
解题卡点:
①有连续目标元素时,一开始写成了下方的while形式,结果到数组末尾索引超出边界了。因此只用1个外层while,内层进行if判断,若满足条件指针+1,回到外层进行循环,若再满足条件再指针+1,回到外层进行循环。此时慢指针不动,而快指针+2,实现用if代替内层while;
while fast <= len(nums)-1:
while nums[fast] == val:
fast += 1
nums[slow] = nums[fast]
slow += 1
fast += 1
# 错误
②如上gif图,快指针指到数组最后一个元素,且该元素需被删除时,索引+1。但快指针指向的元素会被赋值给慢指针,此时nums[slow]=nums[fast]=num[len(nums)],超出索引边界。因此当快指针指到最后一个元素时应停下来。故若元素满足条件,回到while进行判断,若为最后一个元素跳出循环。
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
slow = 0 # 慢指针
fast = 0 # 快指针
while fast <= len(nums)-1: # 指针代表索引,最大索引为len(nums)-1,若fast再大跳出循环
if nums[fast] == val:
fast += 1
continue # 快指针指向目标元素后,回到while循环,防止fast超出索引使下一行报错
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow
# 时间复杂度 O(n)
# 空间复杂度 O(1)
总结:原地移除元素,使用双指针法进行。当快指针指向目标元素时,慢指针不动,快指针+1,同时将快指针指向的除目标元素之外的值赋给慢指针的值。当快指针指向最后一个元素,且慢指针的索引代表着前k个元素的个数。
另一种写法,使用不等于进行if判断,更方便。另外,对nums[fast]和val使用等于和不等于判断的写法不同,需注意。
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
slow = 0
fast = 0
while fast <= len(nums)-1:
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow
# 时间复杂度 O(n)
# 空间复杂度 O(1)
977. 有序数组的平方
题目链接:. - 力扣(LeetCode)
文章讲解:代码随想录
解题卡点:无
双指针法:左右指针指向数组第一个元素和最后一个元素,判断元素平方后大小,倒着填入空白数组,随后指针向数组中心移动。
总结:数组以非递减顺序排序,平方后最大的元素分布在数组两端。左右指针指向数组第一个元素和最后一个元素,判断平方大小后,将最大的值倒着填入空白数组,随后指针向数组中心移动。
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
res = [0]*len(nums) # 空白数组,用于存放结果
idx = len(nums)-1 # 空白数组的索引,将结果倒着填入空白数组
left = 0 # 左指针
right = len(nums)-1 # 右指针
while right >= left: # 循环到最后时左右指针指向相同元素,此时right==left
if nums[right]**2 >= nums[left]**2:
res[idx] = nums[right]**2
right -= 1 # 右指针向数组中心移动
else:
res[idx] = nums[left]**2
left += 1 # 左指针向数组中心移动
idx -= 1
return res
# 时间复杂度 O(n)
# 空间复杂度 O(1)