提单链接:https://leetcode.cn/discuss/post/3578981/ti-dan-hua-dong-chuang-kou-ding-chang-bu-rzz7/
一、定长滑动窗口
对于此类问题,可以归类为同种方法:
即在窗口右侧插入元素,达到窗口给定长度,进行相应操作,推出末尾元素,进行相应操作,继续循环
注意:因为一定要插入和推出元素,所以窗口大小必须大于0,如果窗口大小可能为0,则需要特殊处理
let ans = 0
let count = 0
for(let i = 0;i < arr.length ;i++){ // i 指向当前想要插入窗口的元素
if(k == 0){
return 变量
}
count += arr[i] // 插入后操作,根据题目变化
if(i< k - 1){
continue // 如果窗口长度还未达到指定宽度 - 1,不进行元素退出操作直接开启下一次循环
} //(为何是k - 1 ? 因为i指向的是想要插入窗口的元素,所以i = k -1 时,是第一次定长窗口
// 完整的时刻)
ans = Math.max(ans,count) // 计算结果,根据题目变化
count -= arr[i - k + 1] //末尾元素退出,给下一个插入的元素让位
}
LeetCode例题:
二、不定长滑动窗口
1.求最长/最大
此类题型一般使用思路:
1.逐渐扩展(逐步增大窗口右端点即窗口增大,尽可能包裹更多元素)
2.达到条件(根据题目不同,窗口增大导致达成题干条件,此时右端点因达成条件,无法移动,需要等待左端点操作)
3.逐渐缩小(逐渐增大窗口左端点即减小窗口,直至不再违反条件,而后重复步骤1
注意:此类题型因为要逐渐缩小窗口,所以有记忆先前元素的需求,一般配合哈希表Map使用
let maxlen = 0
const map = new Map()
let left = 0
for (let right = 0; right < nums.length; right++) {
map.set(nums[right],(map.get(nums[right] )|| 0) + 1)
while(map.get(nums[right]) > k){
map.set(nums[left],map.get(nums[left]) - 1)
left++
}
maxlen = Math.max(maxlen,right - left + 1)
}
return maxlen
LeetCode例题:
2.求最短/最小
解题思路同“求最长/最大”,其中的Math.max替换为Math.min
注意:关注Infinity的问题,无穷不能作为输出值,所以需要额外判断
let ans = Infinity
let count = 0
let l = 0
for(let r = 0;r < nums.length;r++){
count += nums[r]
while(count >= target){
ans = Math.min(ans,r - l + 1)
count -= nums[l]
l++
}
}
if(ans == Infinity){
return 0
}else{
return ans
}
LeetCode例题:
3.恰好型滑动窗口
例如,要计算有多少个元素和恰好等于 k 的子数组,可以把问题变成:
计算有多少个元素和 ≥k 的子数组。
计算有多少个元素和 >k,也就是 ≥k+1 的子数组。
答案就是元素和 ≥k 的子数组个数,减去元素和 ≥k+1 的子数组个数。这里把 > 转换成 ≥,从而可以把滑窗逻辑封装成一个函数 f,然后用 f(k) - f(k + 1) 计算,无需编写两份滑窗代码。
总结:「恰好」可以拆分成两个「至少」,也就是两个「越长越合法」的滑窗问题。
注:也可以把问题变成 ≤k 减去 ≤k−1(两个至多)。可根据题目选择合适的变形方式。
注:也可以把两个滑动窗口合并起来,维护同一个右端点 right 和两个左端点 left ,构成三指针滑动窗口
思路代码如下:
const n = nums.length;
let left1 = 0, left2 = 0, right = 0; //维护两个左指针和一个公共右指针,每次右指针循环时得出的左指针,相减即为子数组/子字符串数量
let sum1 = 0, sum2 = 0; //记录两个窗口各自的和,以匹配条件
let ret = 0;
while (right < n) {
sum1 += nums[right];
while (left1 <= right && sum1 > goal) {
sum1 -= nums[left1];
left1++;
}
sum2 += nums[right];
while (left2 <= right && sum2 >= goal) {
sum2 -= nums[left2];
left2++;
}
ret += left2 - left1;
right++;
}
return ret;
LeetCode例题: