二分法
[关于二分]
b站-五点七边 查找范围视为区间,通过边界来获取需要的点
- 将元素分为蓝红,寻找蓝红边界
- 左右指针的不断移动 -> 蓝红区域的拓展
有序数组->二分
关于二分法的前提: 数组为有序数组,同时数组中无重复元素
通过取middle的方式,缩小[l, r]区间定位target值
法一:
def search(self, nums: List[int], target: int) -> int:
# create pointers
n = len(nums)
left, right = 0, n-1
# check the left and right
while left <= right:
# half
middle = (left + right) // 2
if target == nums[middle]:
return middle
elif target < nums[middle]:
right = middle - 1
else:
left = middle + 1
return -1
法二:
如果用left<right,相当于把right指针视为开区间,而middle的计算也需要将right视为开区间进行
改变循环内语句为:
while left < right:
# half
middle = (left + right) // 2
if target == nums[middle]:
return middle
elif target < nums[middle]:
right = middle
else:
left = middle + 1
思路:分开找开始位置和结束位置,即对第一个等于target和最后一个等于target的下标位置进行二分查找。
target存在的情况和标准二分一致
if not, 因为在最后一层while循环中,right指针会被置于恰好小于target的下标-1处。
注意,用right+1而不用middle的原因,right为右区间,即满足条件的位置前一位。
[left, right],return right + 1
快慢指针
注意快慢指针的移动
判断条件 如果用==很难实现,可以尝试用!=进行
思路:快慢指针同时遍历,每次遍历用快指针赋值给慢指针,如果快指针的位置是target,则跳过,从而实现删除。
def removeElement(self, nums: List[int], val: int) -> int:
# double pointers
n = len(nums)
low, fast = 0, 0
while fast < n:
if nums[fast] != val:
nums[low] = nums[fast]
low += 1
fast += 1
return low
快慢指针 (for循环)
n = len(nums)
low = 0
for fast in range(n):
# if val, skip
if nums[fast] == val:
continue
nums[low] = nums[fast]
# move the low pointer
low += 1
return low
暴力
def removeElement(self, nums: List[int], val: int) -> int:
# 暴力
n = len(nums)
i = 0
while i < n:
if nums[i] == val:
for j in range(i, n-1):
nums[j] = nums[j+1]
i -= 1
n -= 1
i += 1
return i