滑动窗口在c++中通常只需用两个下标变量left和right维护边界,配合vector或数组即可;手写双端队列或封装窗口类易引发越界、值更新遗漏、误删元素等错误。

滑动窗口在C++里不用自己手写双端队列
标准库 std::deque 足够用,但多数场景其实连它都不需要——用两个下标变量 left 和 right 维护窗口边界,配合 vector 或原生数组就能搞定。手写链表或封装“窗口类”反而增加出错概率,尤其在边界移动、越界检查、重复元素处理上容易漏判。
常见错误现象:right 超出 size() 还继续访问;left 移动后没及时更新最大值/最小值;窗口收缩时误删了后续还要用的元素。
- 窗口扩张:
right每次加 1,读取arr[right]前先确认right - 窗口收缩:只在不满足条件时移动
left,且left 必须恒成立 - 别把“窗口长度固定”和“窗口大小可变”混用逻辑——前者常用
for (int right = k-1; right ,后者必须用 <code>while动态缩窗
用 unordered_map 记频次时注意 key 的生命周期
滑动窗口常配合哈希表统计字符或数字出现次数,但若用 string 的子串(如 s.substr(i, len))作 unordered_map 的 key,会触发频繁拷贝,性能断崖下跌;更危险的是,若用 const char* 指向临时 string::c_str(),指针很快悬空。
使用场景:找最长无重复子串、最小覆盖子串、最多替换 K 次后的最长重复字符子串等。
立即学习“C++免费学习笔记(深入)”;
- 字符频次直接用
vector<int>(128)</int>更快更安全,ASCII 范围内可直接索引 - 要存字符串 key 时,确保来源是持久对象(如输入参数
const string& s),或改用string_view(C++17+)避免拷贝 - 删 key 前检查计数是否真为 0,
map[key]--后若值为 0,map.erase(key)才能保持 size 准确
INT_MIN / INT_MAX 在窗口最值问题里容易溢出
求滑动窗口最大值时,有人习惯初始化 max_val = INT_MIN,再不断比较更新。但若窗口内全是负数且值极小(比如 -2e9),而 INT_MIN 是 -2147483648,在 32 位环境可能没问题,但一旦数据来自 long long 或题目明确说数值范围达 1e9,就该换用更宽类型。
性能影响:用 long long 不拖慢,但用 numeric_limits<long long>::min()</long> 比硬写数字更清晰。
- 优先用
auto max_val = nums[left]初始化,从窗口第一个元素起步 - 如果必须用极限值,查头文件
<climits></climits>后,选LLONG_MIN/LLONG_MAX,并确保所有参与运算的变量同为long long - 别依赖
INT_MIN + 1这类表达式做哨兵值——整数溢出是未定义行为
LeetCode 第 239 题(滑动窗口最大值)为什么不能只用 priority_queue
因为 priority_queue 不支持按需删除堆中任意元素。窗口滑出一个数时,你无法快速把它从堆顶之外的位置移除,只能等它浮到堆顶再弹出——此时堆里可能积压大量已失效的旧值,导致时间复杂度退化成 O(n log n) 甚至更差。
正确做法是用单调队列:维护一个 deque<int></int> 存下标,保证对应值严格递减。每次 right 进来时,从尾部弹出所有 ≤ 新值的下标;每次 left 移出时,检查队首下标是否已越界,是则弹出。
- 关键点不是“存值”,而是“存下标”——这样才能判断队首是否还在窗口内
- 入队前清尾:
while (!dq.empty() && nums[dq.back()] - 出队前检头:
if (dq.front()










