代码随想录27期|Python|Day2|滑动窗口209(904、76)|螺旋矩阵59

209.长度最小的子数组

思路

滑动窗口:直接运用双指针(同向)方法的框架,fast和slow框起来的就是需要移动的窗口。改变窗口的位置需要移动左右边界。

右边界:fast依次向后遍历即可,所执行的还是“查询”工作,由for in range实现;

左边界:在右边界移动后出现当前的sum >= target的时候移动,缩小子序列范围。注意!这里的移动不是移动一次就交给fast移动了,而是持续移动slow直到sum < target为止,所以我们这里需要的不止是if的一次性判断,而是持续的循环,所以使用while

这里没有采取随想录的return写法,因为太高级了没想到(悲);另外一方面也是flag的用法突然就想到了,所以用一下。

class Solution(object):
    def minSubArrayLen(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        result = 100001  # 题目所示最大的数组长度 
        sublen = 0  # 保存记录当前的子序列长度,用来和上一次的result取最小值
        slow, fast = 0, 0  # 这里还是选取使用快慢指针
        sum = 0  # 保存当前的子序列和
        flag = 0  # 判断result是否发生改变
        for fast in range (len(nums)):
            sum += nums[fast]  # 只要fast移动,就多加一个 
            while sum >= target:  # 注意!!我们要让slow能够“一直往前”缩小区间,就需要一直判断,所以用while不是if
                sublen = fast - slow + 1  # 区间长度,注意是索引的差值 + 1
                result = min(result, sublen)  # 上一轮result和当前的子序列长度取小
                sum -= nums[slow]  # 往前移动slow之前,总和也需要剪掉当前的slow对应的值
                slow += 1  # 往前移动一格
                flag =1  # 表示现在的result被修改了,也就是说存在最小的子序列
        if flag:  # 存在最小的子序列,返回result
            return result
        return 0  # 不存在

904.水果成篮

思路

本题的思路是使用一个哈希表,记录当前的滑动窗口中,每种水果出现的次数“key - value”。由于只能最多出现2种水果,所以在遇到第3种的时候持续移动left,这就是while的判据。

另外,本题使用了一个新的方法Counter():作用就是记录每一个key对应出现的次数,本题单独创建,可以理解为字典。还有一个新的迭代方法enumerate():返回可迭代对象(这里的fruits列表)的每一个元素(x)和对应的索引(right)。

class Solution(object):
    def totalFruit(self, fruits):
        """
        :type fruits: List[int]
        :rtype: int
        """
        cnt = Counter()  
        # 可以理解成一个计数用的字典“key -- value”,其中key是元素的种类,value是该种类出现的次数

        left = 0  # 定义起始点
        ans = 0  # 定义最终长度
        for right, x in enumerate(fruits):  
                        # enumerate迭代器方法:返回第 1 个是索引,第 2 个是迭代对象的内容,在这里x是fruits里面的值,right是对应的位置
            cnt[x] += 1  # 每次right移动,就要在对应的水果种类上 + 1
            while len(cnt) > 2:  
                # 通常情况下,cnt的长度只能是最多3个(元素种类的上限是2)
                cnt[fruits[left]] -= 1  # 位移left的同时需要把对应的计数次数 - 1
                if cnt[fruits[left]] == 0:  # 当key对应的value是0,也就是不存在当前水果的时候,删除这个key
                    cnt.pop(fruits[left])
                left += 1  # 移动left
            ans = max(ans, right - left + 1) # 每次走完一个while,也就是当前只有2个key的时候,记录一下ans最小值
        return ans

76.最小覆盖子串

思路

和上一题一样,我们创建一个哈希表来保存t中的“key - value”。但是涉及到的判断较多:

1、在right每移动1格之后,判断哈希表中对应字符还需要的个数,如果当前right指向的是需要的,即value大于0,那就纳入序列,同时哈希表中对应的value - 1

2、当t的全部字符都被满足(此时right已经纳入了全部的t中的字符个数,长度为0),就需要移动left,这里判断后的循环退出的条件是,当前left移动的位置使得哈希表对应字符的value恰好=0。

class Solution(object):
    def minWindow(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: str
        """
        t_cnt = Counter(t)  # cnt是可变量,开一个哈希表来表示t中的 key - value
        t_len = len(t)  # 可变量,表示当前t的长度,全部包含时 == 0
        
        left = 0  # 左指针在遇到满足条件时移动
        ans = (0, float('inf'))  # 保存当前的左右边界最小的情况,ans[1]是右边界,ans[0]是左边界
        
        for right, x in enumerate (s): 
            if t_cnt[x] > 0:  # 如果此时right所指位置的元素在t中还有“余量”,也就是没有全部包含
                t_len -= 1  # right所指的元素纳入序列,相应的t还需要填充的长度-1
            # Step 1:把当前的x纳入子序列
            t_cnt[x] -= 1
            # Step 2:如果此时t被满足,那么我们就找到了一个“可行的序列”,进入移动
            if t_len == 0:
                while 1:
                    # 判断当前left的元素是否已经满足要求
                    temp = s[left]
                    if t_cnt[temp] == 0:  # 若已经满足“恰好 == 0”,直接退出,因为这个元素是“必要的”,删除会导致不足
                        break
                    
                    t_cnt[temp] += 1  # 如果不是,去掉一个之后相应的元素计数需要+1
                    left += 1
                ans = (left, right) if ans[1] - ans[0] > right - left else ans  # 每次while走完,left更新完保存当前最小的ans
                
        return '' if ans[1] > len(s) else s[ans[0]: ans[1] + 1]

数组总结

本人偷懒,但是看到随想录星球里面已经有老哥总结了mindmap,所以引用如下: 

第二天完结🎉

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值