/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function (s) {
const set = new Set(); //判断滑动窗口内是否有重复元素
let i = 0,//滑动窗口右边界
j = 0,//滑动窗口左边界
maxLength = 0;
if (s.length === 0) {//极端情况
return 0;
}
for (i; i < s.length; i++) {
if (!set.has(s[i])) {//当前元素不在set中 就加入set 然后更新最大长度,i++继续下一轮循环
set.add(s[i]);
maxLength = Math.max(maxLength, set.size);
} else {
//set中有重复元素不断让j++ 并删除窗口之外的元素 直到滑动窗口内没有重复的元素
while (set.has(s[i])) {
set.delete(s[j]);
j++;
}
set.add(s[i]);//放心将s[i]加入set中
}
}
return maxLength;
};

​力扣​

最后更新时间: 2021/09/19

不像动态规划,绝大部分滑动窗口类题目本质上真的不算是难题,经过有效的训练就可以熟练掌握。本文中Eason给大家分享一套滑动窗口的思维框架 (共五步-五连鞭),非常好记和容易理解。掌握它之后,你可以一口气秒杀12道中等难度 的同类型题目 (卧槽?12道?是的,而且给全解析,再不点赞还是人?),从而帮助你再遇见滑动窗口类型题目的时候不再胆怯!

PS:在这里我就不教大家什么是滑动窗口啦,这个概念并不难,leetcode上类似的科普文也有很多,所以我就不班门弄斧了。如果读者完全没有听说过这个概念,烦请先花10分钟弄懂个大概后再来阅读本文

废话不多说,直接上框架 (伪代码)

class Solution:
def problemName(self, s: str) -> int:
# Step 1: 定义需要维护的变量们 (对于滑动窗口类题目,这些变量通常是最小长度,最大长度,或者哈希表)
x, y = ..., ...

# Step 2: 定义窗口的首尾端 (start, end), 然后滑动窗口
start = 0
for end in range(len(s)):
# Step 3: 更新需要维护的变量, 有的变量需要一个if语句来维护 (比如最大最小长度)
x = new_x
if condition:
y = new_y

'''
------------- 下面是两种情况,读者请根据题意二选1 -------------
'''
# Step 4 - 情况1
# 如果题目的窗口长度固定:用一个if语句判断一下当前窗口长度是否达到了限定长度
# 如果达到了,窗口左指针前移一个单位,从而保证下一次右指针右移时,窗口长度保持不变,
# 左指针移动之前, 先更新Step 1定义的(部分或所有)维护变量
if 窗口长度达到了限定长度:
# 更新 (部分或所有) 维护变量
# 窗口左指针前移一个单位保证下一次右指针右移时窗口长度保持不变

# Step 4 - 情况2
# 如果题目的窗口长度可变: 这个时候一般涉及到窗口是否合法的问题
# 如果当前窗口不合法时, 用一个while去不断移动窗口左指针, 从而剔除非法元素直到窗口再次合法
# 在左指针移动之前更新Step 1定义的(部分或所有)维护变量
while 不合法:
# 更新 (部分或所有) 维护变量
# 不断移动窗口左指针直到窗口再次合法

# Step 5: 返回答案
return ...

看不懂? mode问题,在我们做3. 无重复字符的最长子串这道题前先用这个模板先套一道简单题643. 子数组最大平均数 I (不计算到中等题目中,基本的良心还是得有)

如果套完还不懂,不要担心,让我们再套一道,套完仍然不懂,let's 再套一道......

我们有共13 (12中1简) 道题,请相信自己,套着套着,咱们终究会弄懂的!

作者:eason734

著作权归作者所有。商业载请联系作者获得授权,非商业转载请注明出处