leetcode刷题记录【滑动窗口/双指针类题目】—Python代码+详细注释

题目:76. 最小覆盖子串
难度:困难
算法:滑动窗口

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        # 需要两个计数,一个计t中剩下字符的长度,一个计t中每个字符各自的计数
        
        # 字典统计--方法1
        lookup = collections.Counter(t)
        # # 字典统计--方法2
        # lookup = collections.defaultdict(int)
        # for c in t:
        #     lookup[c] += 1
        left, right = 0, 0
        counter = len(t)
        min_len = inf
        ans = ""
        
        while right < len(s):
            if lookup[s[right]] > 0:
                counter -= 1
            # 比如s = [A, B], t = [B],这里遍历A的时候,把lookup[A]至为-1-----------QQQQ
            lookup[s[right]] -= 1
            # print("s[right] = ", s[right], "//  lookup[s[right]] = ", lookup[s[right]])
            right += 1
            while counter == 0:
                if min_len > right - left:
                    min_len = right - left
                    ans = s[left: right]
                # 如果不是里面是字符,对应的lookup[s[start]]是负数,就不会让counter+=1,也就出不了这个循环,所以会不断缩小左边无用的窗口
                # 所以这边判断的时候,lookup[A] != 0,就不会把counter+1跳出循环--------------QQQQ
                if lookup[s[left]] == 0:
                    counter += 1
                # 所以这边在左移窗口的时候不会有其他影响,只是把之前加进来的再移出去--------------QQQQ
                lookup[s[left]] += 1
                left += 1
        return ans

题目:567. 字符串的排列
难度:中等
算法:滑动窗口

class Solution:
    def checkInclusion(self, s1: str, s2: str) -> bool:
        # 字典化s1子串m个字符
        counter1 = collections.Counter(s1)
        left = 0
        right = len(s1) - 1
        # 字典化ss2子串的m-1个字符
        counter2 = collections.Counter(s2[0: right])
        # print(counter1)
        # print(counter2)
        while right < len(s2):
            # 往里面加一次s2[right]的字典统计,这时长度正好和s1的字典化长度一致,可以比较一次了
            counter2[s2[right]] += 1
            # print(counter2)
            # 进行比较,如果相等,可以返回true
            if counter2 == counter1:
                return True
            # 如果上面没相等,移出左边的s2[left]
            counter2[s2[left]] -= 1
            # 此时判断下是不是左边这个字典化为0,是的话要delete才行
            if counter2[s2[left]] == 0:
                # counter2.pop(s2[left])      --------------这么写也行
                del counter2[s2[left]]
            # 窗口同时右移动,保持窗口长度不变
            left += 1
            right += 1
        return False

大佬题解:https://leetcode-cn.com/problems/permutation-in-string/solution/zhu-shi-chao-xiang-xi-de-hua-dong-chuang-rc7d/

题目:438. 找到字符串中所有字母异位词
难度:中等
算法:滑动窗口

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        # 字典化p,长度 len(p)
        counter1 = collections.Counter(p)
        left = 0
        right = len(p) - 1
        # 字典化s,长度 len(p) - 1
        counter2 = collections.Counter(s[0: right])
        ans = []
        while right < len(s):
            # 长度变成 len(p)
            counter2[s[right]] += 1
            # 判断下是否相等
            if counter2 == counter1:
                ans.append(left)
            # 窗口右移
            counter2[s[left]] -= 1
            # delete字典中val为0的
            if counter2[s[left]] == 0:
                del counter2[s[left]]
            # 窗口整体移动
            right += 1
            left += 1
        return ans

题目:11. 盛最多水的容器
难度:中等
算法:双指针

class Solution:
    def maxArea(self, height: List[int]) -> int:
        left = 0
        right = len(height) - 1
        max_area = 0
        while left < right:
            # 计算面积并记录最大面积
            tmp_area = min(height[left], height[right]) * (right - left)
            max_area = max(max_area, tmp_area)
            # 二选一,要用elif,移动高度低的指针
            if height[left] <= height[right]:
                left += 1
            elif height[right] < height[left]:
                right -= 1
        return max_area

题目:128. 最长连续序列
难度:中等
算法:双指针

lass Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        # 特殊情况处理
        if not nums:
            return 0
        if len(nums) == 1:
            return 1
        # 用set去重
        nums = list(set(nums))
        # 排序以方便用双指针
        nums = sorted(nums)
        # 双指针与初始长度,之前没去重的时候,遇到【0,0】tmp_len没有变化,直接统计max_len = 0就错了,所以max_len要初始化乘 = 1
        left, right = 0, 1
        tmp_len, max_len = 1, 1
        while right < len(nums):
            # 等于上一个数则长度增加
            if nums[right] == nums[right - 1] + 1:
                tmp_len = right - left + 1
                max_len = max(max_len, tmp_len)
                right += 1
            # 否则left指针重新从right处计数--left不用来做nums[left]与nums[right]比较,而是用来做index定位窗口长度
            else:
                left = right
                right += 1
        return max_len

题目:15. 三数之和
难度:中等
算法:双指针

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        if len(nums) < 3:
            return []
        ans = []
        nums = sorted(nums)
        for i in range(len(nums)):
            # 去除i出重复情况
            if i >= 1 and nums[i] == nums[i - 1]:
                continue
            left = i + 1
            right = len(nums) - 1
            while left < right:
                if nums[i] + nums[left] + nums[right] == 0:
                    ans.append([nums[i], nums[left], nums[right]])
                    # 去除left处重复情况
                    while left < right and nums[left] == nums[left + 1]:
                        left += 1
                    # 去除right出重复情况
                    while left < right and nums[right] == nums[right - 1]:
                        right -= 1
                    left += 1
                    right -= 1
                elif nums[i] + nums[left] + nums[right] < 0:
                    left += 1
                elif nums[i] + nums[left] + nums[right] > 0:
                    right -= 1
        # ans = list(set(ans))---不可行,报错
        return ans

题目:2105. 给植物浇水 II
难度:中等
算法:双指针

# 2022.08.14
class Solution:
    def minimumRefill(self, plants: List[int], capacityA: int, capacityB: int) -> int:
        # 双指针
        n = len(plants)
        position_a, position_b = 0, n - 1
        remain_a, remain_b = capacityA, capacityB
        ans = 0
        # 没相遇时,各自计算
        while position_a < position_b:
            # 情况一:如果没超过容量,直接减去
            if remain_a >= plants[position_a]:
                remain_a -= plants[position_a]
            # 必须是elif,如果是if的话会挨个判断
            # 情况二:如果超过容量,加满容量后再减去
            elif remain_a < plants[position_a]:
                remain_a = capacityA - plants[position_a]
                ans += 1
            # 左指针右移
            position_a += 1
            # 同情况一
            if remain_b >= plants[position_b]:
                remain_b -= plants[position_b]
            # 同情况二
            elif remain_b < plants[position_b]:
                remain_b = capacityB - plants[position_b]
                ans += 1
            # 右指针左移
            position_b -= 1
        
        # 如果奇数相遇,单独判断一次,且只判断加水情况,不加水的不做任何处理就可以了
        if position_a == position_b:
            if remain_a >= remain_b and remain_a < plants[position_a]:
                ans += 1
            if remain_a < remain_b and remain_b < plants[position_b]:
                ans += 1
        return ans
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值