当前位置: 首页 > news >正文

为什么滑动窗口总能把人写红温?

哈喽大家好,我是程序员脚趾

算法里有一种东西特别恶心。

你看题解的时候:

哦~ 原来是这样。

等自己打开 LeetCode:

left++ 还是 right++ 来着?

然后开始:

  • 调半小时

  • 输出一屏 debug

  • 最后发现 valid 少减了一次

没错,我说的就是滑动窗口。

很多人第一次学这个算法,都有一种错觉:

“我会了。”

实际上:

“你只是看会了。”

真正自己写的时候:

while (right < s.length()) {

刚敲出来,人已经开始慌了。

这篇文章咱就不搞那种教科书式废话了。

什么:

滑动窗口是一种在线性时间内解决子串问题的算法思想。

这种话看了和没看一样。

咱今天直接用人话聊。

你读完至少能做到一件事:

以后再碰到子串问题,不会第一时间原地去世。

顺便还能解决这几个经典题:

LeetCode题目难度
76最小覆盖子串Hard
567字符串排列Medium
438找所有字母异位词Medium
3无重复字符最长子串Medium

一、滑动窗口到底是个啥

先问你个问题。

如果让你找:

一个数组里满足条件的连续子数组

你会咋写?

大部分人的第一反应:

for (...) { for (...) { } }

暴力枚举。

简单,直接,且超时。

时间复杂度直接干到O(N²)

LeetCode 看了都摇头。

于是聪明人就发现:

很多区间,其实没必要重复计算。

比如:

[left, right]

已经算过了。

下一次你变成:

[left, right + 1]

其实只多了一个元素。

那我干嘛重新算一遍?

于是滑动窗口就诞生了。

说白了:

用一个会移动的区间,维护当前答案。

窗口右边负责扩张。

窗口左边负责收缩。

像极了一只毛毛虫。

一会伸长。

一会缩短。

然后边爬边找答案。


二、为什么它是 O(N)

很多人看到这个:

while () { while () { } }

立马PTSD发作:

双 while? 那不还是 O(N²)?

其实不是。

因为:

left 和 right 都不会后退。

它俩这一生只有一个梦想:

向右走。

每个元素:

  • 最多进窗口一次

  • 最多出窗口一次

所以整体复杂度其实是O(N)

这就是滑动窗口最牛逼的地方。


三、滑动窗口万能模板

这玩意其实是有固定套路的。

以后你刷题,别硬想。

直接默写模板。

int left = 0, right = 0; while (right < s.length()) { // 1. 右边字符进入窗口 char c = s.charAt(right); right++; // 2. 更新窗口数据 // 3. 判断是否需要收缩 while (窗口不合法) { char d = s.charAt(left); left++; // 4. 更新窗口数据 } // 5. 更新答案 }

别看简单。

实际上整个滑动窗口,核心就三件事:

1、什么时候扩大窗口 2、什么时候收缩窗口 3、什么时候更新答案

你只要把这三个问题想明白。

代码基本不会错。

真正容易死的地方其实是:

答案到底在哪更新?

有的题:

  • 扩张时更新

  • 收缩时更新

  • 收缩结束后更新

第一次写的时候特别容易脑子打结。


四、最经典的一题:最小覆盖子串

题目大概意思:

给你:

s = "ADOBECODEBANC" t = "ABC"

让你找:

s 里最短的一个子串

要求它必须包含:

A、B、C

答案:

BANC

这题第一次做的时候,很多人都会陷入一种状态:

我知道是滑动窗口。 但我不知道窗口里该存啥。

于是开始瞎写。

然后 valid 当场爆炸。


五、need 和 window 到底是干啥的

这个地方其实特别简单。

你只需要记住:

need:目标欠款 window:当前余额

比如:

t = "AABC"

那么:

need: A -> 2 B -> 1 C -> 1

意思就是:

A 还欠两个 B 欠一个 C 欠一个

而 window 就表示:

当前窗口里有多少。

窗口右边扩张:

window.put(c, window.getOrDefault(c, 0) + 1);

窗口左边收缩:

window.put(d, window.get(d) - 1);

整个算法本质上:

就是在讨债。

欠款补齐了。

窗口合法。

开始缩。

缩到快不合法的时候停下。


六、valid 到底是什么鬼

这玩意第一次看特别抽象。

其实它翻译成人话就一句:

当前有几个字符已经还清贷款了。

比如:

need: A -> 1 B -> 1 C -> 1

当前窗口:

A -> 1 B -> 1 C -> 0

那说明:

A 和 B 已经达标

于是:

valid = 2

当:

valid == need.size()

说明:

所有贷款全部还完

窗口合法。

开始收缩。


七、最容易写错的地方

很多人会问:

为啥更新答案放在 while 里面?

因为:

窗口合法的时候,才是候选答案。

而我们要的是:

最短。

所以窗口一合法:

立马开始压缩。

就像搬家收纳。

能扔的全扔。

直到再扔就不合法了。

这时候留下的。

才是当前最优解。


八、完整代码

class Solution { public String minWindow(String s, String t) { Map<Character, Integer> need = new HashMap<>(); Map<Character, Integer> window = new HashMap<>(); for (char c : t.toCharArray()) { need.put(c, need.getOrDefault(c, 0) + 1); } int left = 0, right = 0; int valid = 0; int start = 0; int len = Integer.MAX_VALUE; while (right < s.length()) { char c = s.charAt(right); right++; if (need.containsKey(c)) { window.put(c, window.getOrDefault(c, 0) + 1); if (window.get(c).equals(need.get(c))) { valid++; } } while (valid == need.size()) { if (right - left < len) { start = left; len = right - left; } char d = s.charAt(left); left++; if (need.containsKey(d)) { if (window.get(d).equals(need.get(d))) { valid--; } window.put(d, window.get(d) - 1); } } } return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len); } }

九、真正的滑动窗口思维

很多人学算法。

喜欢背模板。

其实没啥用。

因为一变题就寄。

真正重要的是:

窗口什么时候合法?

你只要能判断:

  • 什么时候扩张

  • 什么时候收缩

  • 什么时候更新答案

那这个题就已经做出来一半了。

后面的:

  • 字符串排列

  • 找异位词

  • 最长无重复子串

本质上全是这一套。

只是条件变了而已。


十、最后送你一句话

我后来发现。

滑动窗口其实就一句话:

right 负责把答案搞出来。
left 负责把答案榨干。

窗口不合法:

right 往前冲。

窗口合法:

left 开始疯狂压缩。

直到榨不动。

这时候留下的。

就是当前最优解。

很多题你一旦用这个视角去看。

会突然发现:

卧槽,原来全长一个样。

这才是滑动窗口真正的套路。

http://www.jsqmd.com/news/828054/

相关文章:

  • 赣州 GEO 科普|AI 时代品牌信息基建,七文 GEO 助力品牌长效可见
  • 如何构建智能的多显示器窗口布局持久化解决方案
  • 使用Taotoken后API调用延迟与稳定性观测体验分享
  • 合泰单片机开发环境搭建保姆级教程:HT-IDE3000与HOPE3000安装避坑指南
  • 免费在线 AVIF 转 WebP 工具推荐|无需上传、保护隐私的高效图片格式解决方案
  • 快速迭代的 AI 应用项目如何借助 Taotoken 实现模型热切换与降级
  • 从PostgreSQL迁移到openGauss后,我的Navicat连接配置踩了哪些坑?
  • ncmdumpGUI:免费一键转换网易云音乐ncm格式的终极指南
  • MoviePilot批量重命名:5步解决NAS媒体库命名混乱问题
  • 基于DingTalk-OpenClaw连接器快速构建企业级AI机器人
  • 一对老金耳环引发的折腾:在绍兴,我最终选了福正美 - 福正美黄金回收
  • 宁波金价996,六家回收报价差多少?福正美最高 - 福正美黄金回收
  • D2DX暗黑2宽屏补丁:3分钟让经典游戏焕发新生的终极优化方案
  • 【Auto CAD 2020】单张打印输出PDF图纸A0、A1尺寸,黑白颜色
  • 使用企业微信的客户群,生成永久企业群立牌二维码,解决微信群二维码有效期只有7天问题【基于永久立牌二维码生成7天动态群二维码】】
  • 终极指南:如何用开源缠论量化工具实现专业级交易可视化
  • 在自动化客服系统中集成多模型API以提升响应灵活性
  • 2026年论文AIGC率高怎么降?最新10个免费降ai率工具亲测(附降低ai率方法) - 降AI实验室
  • 别再只盯着网线了!聊聊机房里的‘电话线’:大对数线缆的选型、端接与测试全攻略
  • 宁波黄金回收省钱实测:6家渠道比价,福正美真省 - 福正美黄金回收
  • 非标设备集成指南:如何用德创V+平台统一管理相机、PLC和视觉算法
  • 2026年广州地址变更代办,哪家财税公司好用? - 速递信息
  • SIM800C模块硬件连接避坑指南:从USB-TTL调试到STM32F407实战接线
  • 【RT-DETR实战】039、损失函数改进:Varifocal Loss替换Focal Loss
  • 【从零学Vibe Coding】第二章:大模型到底是怎么工作的(小白版)
  • 纸板快速原型设计:从材料科学到工程实践的创客指南
  • DGX平台Spark数据处理优化:GPU加速与RAPIDS集成实战
  • 即梦视频水印(怎么去除)福气满满去水印小程序(简单好用.终身免费) - 政企云文档
  • F5 Qtrax漏洞深度解析:50+漏洞批量爆发,多个RCE高危,政企网关安全告急
  • idea里创建maven的web项目