# 小记滑动窗口
5 min read
Table of Contents
滑动窗口法
所需变量
滑动窗口由三部分构成:边界,条件相关变量,需求记录变量。
边界
边界由两个指针构成,分别称为左边界和右边界。
条件相关变量
条件相关变量是用于存储题目所需条件数值的变量。(例如区间和,区间长)
需求记录变量
需求记录变量是用于算法计划返回的变量,也是题目需求的变量,通常是最大值或最小值(例如区间和最大值,或是满足条件的区间最长长度)
方法步骤
听好了,我只写一遍。
- 所需变量声明
- 进行循环,在循环中不断移动右边界,同时不断更新条件相关变量
- 在每次移动右边界后,检查条件相关变量是否满足需求记录变量,如果满足则进入另一个循环。
- 在另一个循环中,左边界不断移动,更新条件相关变量,记录需求记录变量,直到条件相关变量不满足条件,循环破坏,回到右边界移动的大循环
- 需求记录变量为所求
去跟小伙伴们吹逼
更加易懂的代码版本(也就是模板代码):
def sumWindow(nums: List[int]) -> nums: # 窗口左右边界 left = 0 right = 0 # 条件相关变量 sum = 0 # 以窗口内元素总和为示例 res = 0 # 以求最大元素总和为例
# 遍历 while right < len(nums): # 更新值 sum += nums[right]
# 如果满足条件,则左边界移动,遍历并记录,直至破坏条件 while sum > target: # 记录最大值 res = max(sum,res) # 左边界移动,更新 sum sum -= nums[left] left += 1
# 右边界移动 right += 1
return res # 别高兴到忘了返回...论为什么滑动窗口比暴力快
猜测上,滑动窗口采用了一种特别的遍历方法,能够在有效排除不符合条件的组合的同时不排除满足条件的组合。
由于满足条件的数组之间存在有一定相似性,滑动窗口法通过利用这个相似性——在两端移动过程中处于满足条件和不满足条件之间反复横跳,以高效遍历所有可能的组合。
经典为例
给定一个含有 n 个正整数的数组和一个正整数 target。找出该数组中满足其总和大于等于 target 的长度最小的子数组
[numsl, numsl+1, ..., numsr-1, numsr],并返回其长度。如果不存在符合条件的子数组,返回0。示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
显然可以使用暴力解法,但是本文在此不做提及。
class Solution: def minSubArrayLen(self, target: int, nums: List[int]) -> int: # 滑动窗口法 left = 0 # 左边界 right = 0 # 右边界 sum = 0 # 条件相关变量(区间和) ret = 0 # 需求记录变量(区间和最大值) length = len(nums)
while right < length: # 稳定往窗口加数 # 右边界无条件移动,并且移动时计算当前的条件相关变量值 sum += nums[right] right += 1
# 满足题目条件记录下来,然后 持续 往窗口减数 # 仅在条件相关变量满足条件时执行,左边界移动,破坏满足的条件,并记录需求记录变量 while sum >= target: # 记录 if ret == 0: ret = right - left else: ret = min(ret, right - left)
# 减数 sum -= nums[left] left += 1
return ret