滑动窗口学习笔记:长度最小的子数组,无重复字符的最长子,乘积小于 K 的子数组

参考:滑动窗口【基础算法精讲 03】_哔哩哔哩_bilibili

ps:笔记按本人理解整理,重思路,跟原视频代码有些不同

【如果笔记对你有帮助,欢迎关注&点赞&收藏,收到正反馈会加快更新!谢谢支持!】

目录

题目一:长度最小的子数组  【找最短】

 题目2: 无重复字符的最长子串 【找最长】

题目3: 乘积小于 K 的子数组 【方案数】

 往期笔记:


题目1:长度最小的子数组  【找最短】

209. 长度最小的子数组 - 力扣(LeetCode)

  • 思路:先增加窗口满足“和>= target”,再缩小窗口找最小
  • 拆解:
    • 如何表示滑动窗口:由左指针(left) 和右指针(right) 划定窗口区间
    • 如何移动窗口:先固定一边,再移动另一边【设先固定right,再移动left】
    • 右指针向右移动:增大窗口 → 总和增加 
      左指针向右移动:减小窗口 → 总和减小
    • 先增大窗口【右指针带领窗口右移】  → 再减小窗口【让窗口满足条件】
  • 代码:
    class Solution:
        def minSubArrayLen(self, target: int, nums: List[int]) -> int:
            left = 0 
            right = 0
            result = inf   # 找最小区间长度,所以初始化为无穷大
            sum_ = 0
            
            while right < len(nums):  # 先定下右边
                sum_ += nums[right]
                
                while sum_ >= target:  # 固定right之后移动left来缩小窗口(移动的前提是满足sum_ >= target的条件)
                    result = min(result, right-left+1)  # +1是因为left和right指向同一个num时表示长度为 1 的区间
                    sum_ -= nums[left]
                    left += 1
                
                right += 1  # sum_<target时再增大窗口,让他满足条件 
    
            return result if result != inf else 0

 题目2: 无重复字符的最长子串 【找最长】

3. 无重复字符的最长子串 - 力扣(LeetCode)

  • 变化:找最短 → 找最长【窗口缩到最短取结果 → 窗口扩到最长取结果】
  • 拆解:
    • 右指针右移【扩增窗口】→ 如右指针的数已在窗口中【已到当前最大】 → 左指针右移【缩小窗口】→ 直至右指针的数不在窗口【满足可以继续扩增条件】 → 左指针固定,继续移动右指针【扩增窗口】
  • 代码:
    class Solution:
        def lengthOfLongestSubstring(self, s: str) -> int:
            left = 0
            right = 0
            result = 0
    
            while right < len(s):
                # 窗口为s[left: right],不包含right指的数
                while left < right and s[right] in s[left: right]:
                    left += 1
    
                result = max(result, right - left + 1)
                right += 1
    
            return result
    

题目3: 乘积小于 K 的子数组 【方案数】

713. 乘积小于 K 的子数组 - 力扣(LeetCode)

  • 变化:找最大/最小窗口 → 总方案数
  • 拆解:
    • 右指针右移【扩增窗口】→ 直到乘积 >k
    • 左指针右移【缩小窗口】→ 直到乘积 <=k  → 记录方案数
    • 方案数 = right - left + 1 (比如 [3, 2, 5]这个窗口满足条件,那么总共有[3, 2, 5], [2, 5], [5] 共三个方案,最右边固定)
  • 代码:
    class Solution:
        def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
            left = 0 
            right = 0
            result = 0
            multiple = 1  # 记录乘积
    
            while right < len(nums):
                multiple *= nums[right]  
                
                # 如不满足条件,缩小窗口至刚满足条件
                while multiple >= k and left <= right:
                    multiple /= nums[left]
                    left += 1
                
                result += right-left+1
                right += 1   # 扩大窗口
            
            return result
    

 往期笔记:

相向双指针学习笔记(一):两数之和 II ,三数之和_算法笔记 两数之和-CSDN博客

相向双指针学习笔记(二):盛最多水的容器,接雨水-CSDN博客

 二分查找学习笔记(一):在排序数组中查找元素的第一个和最后一个位置-CSDN博客

二分查找学习笔记(二):正整数和负整数的最大计数,咒语和药水的成功对数,H 指数 II-CSDN博客

二分查找学习笔记(三):寻找峰值,寻找峰值II-CSDN博客

二分查找学习笔记(四):寻找旋转排序数组中的最小值I & II,搜索旋转排序数组-CSDN博客

区间DP学习笔记:最长回文子序列,多边形三角剖分的最低得分-CSDN博客

状态机DP学习笔记-CSDN博客

树形DP学习笔记(一):树的路径问题-CSDN博客

树形DP学习笔记(二):打家劫舍III & 监控二叉树-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值