避坑指南:STM32G473 BootLoader开发中,Flash分区与中断向量表重定向的那些坑
2026/5/31 11:33:30
滑动窗口 = 面试 & 刷题里性价比最高的算法之一
什么时候用 → 本质 → 固定窗口 → 变长窗口 → 判断口诀
当你在一个“连续区间”上,反复计算某个指标,且每次只移动一点点时,就该想到滑动窗口。
关键词只有三个:
连续 + 区间 + 重复计算你看到题目里出现这些描述,第一反应就该是它👇
| 题目描述 | 为什么 |
|---|---|
| 连续子数组 / 子串 | 区间连续 |
| 长度固定 k | 固定窗口 |
| 至多 / 至少 | 窗口可变 |
| 最大 / 最小 / 最优 | 比较窗口结果 |
| 每次移动一步 | 可复用上一次结果 |
枚举所有区间 → 每个区间重新算一遍
O(n²) 或 O(n³)我不重新算
我只:
- 加一个新元素
- 删一个旧元素
O(n)这就是它的全部灵魂。
长度为 k 的子数组,最大和是多少?
for(i)for(j=i..i+k-1)sum+=nums[j];intwindowSum=0;// 初始化第一个窗口for(inti=0;i<k;i++){windowSum+=nums[i];}intmax=windowSum;// 开始滑动for(inti=k;i<n;i++){windowSum+=nums[i];// 加右边windowSum-=nums[i-k];// 减左边max=Math.max(max,windowSum);}右边进,左边出,窗口长度始终不变
最短子数组,使得和 ≥ target
intleft=0;intsum=0;intminLen=Integer.MAX_VALUE;for(intright=0;right<n;right++){sum+=nums[right];while(sum>=target){minLen=Math.min(minLen,right-left+1);sum-=nums[left];left++;}}右扩张满足条件,左收缩寻找最优
| 情况 | 用法 |
|---|---|
| 长度固定(k) | 固定窗口 |
| 长度不固定 | 可变窗口 |
| 要最大 / 最小 | 两者都可能 |
| 至多 / 至少 | 可变窗口 |
你那题本质是:
长度为 k 的区间,最大“增量”是多少
✔ 连续
✔ 长度固定
✔ 比最大值
👉100% 固定滑动窗口
看到题目,问自己 3 个问题:
1. 要不要连续? 2. 窗口会不会整体右移? 3. 能不能用“加一个、减一个”更新结果?三问全是「是」👇
直接滑动窗口,不要想 DP
// initfor(inti=0;i<k;i++){window+=arr[i];}ans=window;// slidefor(inti=k;i<n;i++){window+=arr[i];window-=arr[i-k];ans=Math.max(ans,window);}left=0;for(right=0..n-1){add(arr[right]);while(invalid()){remove(arr[left++]);}updateAnswer();}滑动窗口不是一种技巧,而是一种“拒绝重复计算”的思维方式
给你一个数组,找长度为 k 的连续子数组,使它们的和最大。
枚举所有区间 → 每个重新算和 → O(n²)“长度固定 + 连续 + 最大” → 固定滑动窗口
1. 先算第一个窗口 2. 右边进一个 3. 左边出一个 4. 更新答案intwindowSum=0;// 1. 初始化窗口for(inti=0;i<k;i++){windowSum+=nums[i];}intmaxSum=windowSum;// 2. 开始滑动for(inti=k;i<nums.length;i++){windowSum+=nums[i];// 右进windowSum-=nums[i-k];// 左出maxSum=Math.max(maxSum,windowSum);}固定窗口 = for + 加一个 + 减一个
找一个最短的连续子数组,使得和 ≥ target
这里窗口长度不固定
但有一个非常关键的特性:
窗口越大,和只会越大(正数数组)
这叫单调性
一看到这个,就能用滑动窗口
右指针:负责扩张 → 直到满足条件 左指针:负责收缩 → 尝试变短intleft=0;intsum=0;intminLen=Integer.MAX_VALUE;for(intright=0;right<nums.length;right++){sum+=nums[right];// 扩张窗口while(sum>=target){minLen=Math.min(minLen,right-left+1);sum-=nums[left];// 收缩窗口left++;}}“满足条件 → 左边能不能再缩?”
找一个最长的子串,里面没有重复字符
不是 sum,而是:
窗口内字符的出现次数用HashSet或Map
Set<Character>set=newHashSet<>();intleft=0;intmaxLen=0;for(intright=0;right<s.length();right++){charc=s.charAt(right);// 出现重复 → 收缩左边while(set.contains(c)){set.remove(s.charAt(left));left++;}set.add(c);maxLen=Math.max(maxLen,right-left+1);}“不合法 → 一直动左边,直到合法”
| 题 | 类型 | 你该想到什么 |
|---|---|---|
| 最大和 | 固定窗口 | 加一个,减一个 |
| 最短满足 | 可变窗口(至少) | 右扩张,左收缩 |
| 无重复 | 可变窗口(约束) | 违规就缩 |
看到题目,心里过这 4 句:
1. 连续吗? 2. 能不能整体右移? 3. 能不能用“加一个、减一个”维护状态? 4. 是否存在“满足条件 / 不满足条件”的边界?✔ 全是 →滑动窗口
滑动窗口不是算法,是“不重复计算”的习惯