滑动窗口问题要点:
- 方法一:使用高效容器快速维护元素离开窗口和加入窗口后的信息(映射表、平衡树、单调队列等)
- 方法二:分段和分块处理
滑动窗口是一种在算法中常用的技巧,主要用来处理具有连续性的子数组或子序列问题。通过滑动窗口,可以在一维数组或字符串上维护一个固定或可变长度的窗口,逐步移动窗口,避免重复计算,从而提升效率。常用于求解子数组的最大/最小值、满足条件的子数组个数等问题。
算法框架
以下是滑动窗口算法的通用框架:
滑动窗口算法框架
void slidingWindow(string s, string t) {
unordered_map<char, int> need, window;
for (char c : t) need[c]++;
int left = 0, right = 0;
int valid = 0;
while (right < s.size()) {
// c 是将移入窗口的字符
char c = s[right];
// 右移窗口
right++;
// 进行窗口内数据的一系列更新
...
/*** debug 输出的位置 ***/
printf("window: [%d, %d)\n", left, right);
/********************/
// 判断左侧窗口是否要收缩
while (window needs shrink) {
// d 是将移出窗口的字符
char d = s[left];
// 左移窗口
left++;
// 进行窗口内数据的一系列更新
...
}
}
}
在这个框架中,`right` 指针用于扩展窗口,`left` 指针用于收缩窗口。通过不断地移动这两个指针,可以遍历数组或字符串的所有可能子数组或子字符串。
### 示例代码
下面是一个具体的例子,用于计算数组中长度为 `k` 且平均值大于等于 `threshold` 的子数组的个数:
class Solution {
public:
int numOfSubarrays(vector<int>& arr, int k, int threshold) {
int ans = 0;
int s = 0; // 维护窗口元素和
for (int i = 0; i < arr.size(); i++) {
// 1. 进入窗口
s += arr[i];
if (i < k - 1) { // 窗口大小不足 k
continue;
}
// 2. 更新答案
ans += s >= k * threshold;
// 3. 离开窗口
s -= arr[i - k + 1];
}
return ans;
}
};
在这个例子中,通过维护一个固定长度为 `k` 的窗口,不断地移动窗口,计算窗口内元素的和,并判断平均值是否大于等于 `threshold`,从而统计满足条件的子数组的个数。
输入输出要求
以【2024年华为OD机试】 (C卷,100分)- 滑动窗口最大和为例,其输入输出要求如下:
- 第一行输入一个正整数 `N`,表示整数个数(`0 < N < 100000`)。
- 第二行输入 `N` 个整数,整数的取值范围为 `[-100, 100]`。
- 第三行输入一个正整数 `M`,`M` 代表窗口的大小,`M <= 100000`,且 `M <= N`。
3174

被折叠的 条评论
为什么被折叠?



