滑动窗口在C++中直接用两个整型变量left和right下标维护窗口边界最直接;固定长度时可省略left,用i−k隐式表示;变长窗口需用while循环收缩left以确保条件合规,避免erase或切片等高开销操作。

滑动窗口在C++数组中用什么结构最直接
原生数组本身不带滑动能力,必须靠下标手动维护窗口边界。最常用、最轻量的做法是用两个整型变量 left 和 right 表示当前窗口的左右闭区间(或左闭右开),配合循环移动它们来模拟滑动。
别一上来就想着封装成类或用 deque —— 简单查找(比如找最大值、求和、判断子数组是否满足某条件)直接用双指针下标操作,零额外开销,也最容易调试。
-
right每次向右扩展一位,代表“加入新元素” -
left在满足特定条件时向右收缩,代表“踢出旧元素” - 窗口长度就是
right - left + 1(闭区间)或right - left(左闭右开) - 所有访问都通过
arr[left]、arr[right]等下标进行,不拷贝数据
怎么写一个固定长度的滑动窗口求和
这是最典型的入门场景:给定数组 nums 和长度 k,求每个长度为 k 的连续子数组的和。关键在于避免重复计算——先算第一个窗口和,之后每次只减去左边移出的、加上右边移入的。
vector<int> slidingSum(const vector<int>& nums, int k) {
if (k > nums.size()) return {};
vector<int> res;
int window_sum = 0;
// 初始化第一个窗口
for (int i = 0; i < k; ++i) window_sum += nums[i];
res.push_back(window_sum);
// 滑动:i 是 right 指针,对应新加入的右端元素下标
for (int i = k; i < nums.size(); ++i) {
window_sum = window_sum - nums[i - k] + nums[i];
res.push_back(window_sum);
}
return res;
}注意 i - k 就是当前要移出的 left 位置,不需要单独维护 left 变量——因为长度固定,left = i - k 始终成立。
立即学习“C++免费学习笔记(深入)”;
变长窗口怎么控制 left 收缩条件
当窗口长度不固定(比如“最长不含重复字符的子串”),left 的移动就依赖运行时判断。核心逻辑是:每次 right 移动后,检查窗口是否违规;若违规,就持续右移 left 直到合规。
常见错误是把收缩逻辑写成 if 而不是 while——违规可能不止一个元素导致,必须清干净。
- 用
unordered_map<int, int>记录当前窗口内各元素出现次数 -
right每次加一个元素后,更新其计数 - 只要
map[nums[right]] > 1,就执行while (left <= right && map[nums[left]] > 1)并递减map[nums[left++]] - 别忘了在 while 里也要做
map[nums[left]]--,否则死循环
为什么不用 vector::erase 或 subvector 切片
有人想用 vector 的 erase 删除头部、再 push_back 新元素来模拟滑动——这会导致 O(n) 时间复杂度的内存搬移,完全失去滑动窗口的 O(1) 扩展优势。
同理,用 vector(nums.begin()+left, nums.begin()+right+1) 实时构造子数组,等于每次都分配新内存、复制数据,时间和空间都爆炸。滑动窗口的本质是“复用原数组内存+仅移动逻辑边界”,所有花哨的容器封装或切片操作都在违背这个前提。
真正需要动态增删且查最值时(比如滑动窗口最大值),才考虑 deque 存下标;但那已是进阶需求,和基础查找不是一回事。


















