滑动窗口多用于子串相关操作,求解步骤如下:
- 我们在字符串 S 中使⽤双指针中的左右指针技巧,初始化 left = right = 0,把索引左闭右开区间[left, right) 称为⼀个「窗⼝」。
- 我们先不断地增加 right 指针扩⼤窗⼝ [left, right),直到窗⼝中的字符串符合要求(包含了 T 中的所有字符)。
- 此时,我们停⽌增加 right,转⽽不断增加 left 指针缩⼩窗⼝ [left, right),直到窗⼝中的字符串不再符合要求(不包含 T 中的所有字符了)。同时,每次增加 left,我们都要更新⼀轮结果。
- 重复第 2 和第 3 步,直到 right 到达字符串 S 的尽头。
核心在于判断什么条件下需要增大窗口(right++),什么条件下需要缩小窗口(left++)
更加详细的介绍可参考滑动窗口详解,下面两道题都可用滑动窗口求解,可以借此理解对上述两个条件的判断。
567. 字符串的排列
解法:滑动窗口
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
left, right = 0, 0
valid = 0
needs = defaultdict(int)
for char in s1:
needs[char] += 1
windows = defaultdict(int)
while right < len(s2):
if s2[right] in needs:
windows[s2[right]] += 1
if windows[s2[right]] == needs[s2[right]]:
valid += 1
right += 1
# print(valid)
while valid == len(needs):
# print(left, right)
if right - left == len(s1):
return True
if s2[left] in windows:
if windows[s2[left]] == needs[s2[left]]:
valid -= 1
windows[s2[left]] -= 1
left += 1
return False
3. 无重复字符的最长子串
解法:滑动窗口
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
left, right = 0, 0
valid = 0
result = float("-inf")
windows = defaultdict(int)
while right < len(s):
windows[s[right]] += 1
while windows[s[right]] > 1:
if right - left > result:
result = right - left
windows[s[left]] -= 1
left += 1
right += 1
return max(result, right-left)