算法训练营 Day 01| 二分法、双指针法

704 阅读1分钟
二分法

[关于二分]

b站-五点七边 查找范围视为区间,通过边界来获取需要的点

  • 将元素分为蓝红,寻找蓝红边界
  • 左右指针的不断移动 -> 蓝红区域的拓展

704. 二分查找

有序数组->二分

关于二分法的前提: 数组为有序数组,同时数组中无重复元素

通过取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的下标位置进行二分查找。

35.搜索插入位置

target存在的情况和标准二分一致

if not, 因为在最后一层while循环中,right指针会被置于恰好小于target的下标-1处。

注意,用right+1而不用middle的原因,right为右区间,即满足条件的位置前一位。

[left, right],return  right + 1
快慢指针

27. 移除元素

注意快慢指针的移动

判断条件 如果用==很难实现,可以尝试用!=进行

思路:快慢指针同时遍历,每次遍历用快指针赋值给慢指针,如果快指针的位置是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