滑动窗口基本概念
滑动窗口基于双指针的思想,由两个指针指向的元素之间形成一个窗口。 主要用于解答数组或字符串类问题。
故窗口可分为两类:一是固定大小类的窗口:二是大小动态变化的窗口。
窗口主要是通过指针的移动形成。
1、刚开始左右指针left,right都指向第0个元素,窗口为左闭右开的[left,right)区间,所以初始窗口[0,0)区间没有任何元素;
2、开始循环遍历所有元素,判断当前right指针是否超过整个数组的长度,若超出则退出循环,否则执行第3步;
3、然后right指针开始向右移动一个长度,同时更新窗口内的元素;
4、当窗口区间的数据满足要求时,右指针right保持不变,左指针left开始移动,直到移动到一个不再满足要求的区间时,left不再移动位置;
5、然后执行第2步循环。
参考力扣解题中一个回答(强烈推荐该回答!给了很多例子看完真的理解的更深):
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 ...
根据以上作者提供的伪代码来解决**无重复字符的最长子串**问题。
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
s = "pwwkew"
max_len, hashmap = 0, {}
# Step 2: 定义窗口的首尾端 (start, end), 然后滑动窗口
start = 0
for end in range(len(s)):
# Step 3
# 更新需要维护的变量 (max_len, hashmap)
# i.e. 把窗口末端元素加入哈希表,使其频率加1,并且更新最大长度
hashmap[s[end]] = hashmap.get(s[end], 0) + 1 #该元素第一次出现时赋值为0然后加1,第二次出现时不再赋值,直接加1
if len(hashmap) == end - start + 1: #当哈希表长度和窗口长度一致时,表示该窗口中元素各不相同,更新max_len
max_len = max(max_len, end - start + 1)
# Step 4:
# 根据题意, 题目的窗口长度可变: 这个时候一般涉及到窗口是否合法的问题
# 这时要用一个while去不断移动窗口左指针, 从而剔除非法元素直到窗口再次合法
# 当窗口长度大于哈希表长度时候 (说明存在重复元素),窗口不合法
# 所以需要不断移动窗口左指针直到窗口再次合法, 同时提前更新需要维护的变量 (hashmap)
while end - start + 1 > len(hashmap): #窗口长度大于哈希表长度时表示哈希表中有重复的元素,这时需要移动左指针
head = s[start]
hashmap[head] -= 1
if hashmap[head] == 0:
del hashmap[head]
start += 1
# Step 5: 返回答案 (最大长度)
print(max_len)