滑动窗口标准答案¶
记忆核心:右指针负责扩张,左指针负责把窗口修回合法状态。窗口题一定要先说清楚“合法条件”。
3 无重复字符的最长子串¶
- 题目:找字符串中不含重复字符的最长连续子串长度。
- 思路:窗口
[l, r]保持不重复;遇到重复字符,就把左边界跳到上次出现位置之后。 - 标准答案:
class Solution:
def lengthOfLongestSubstring(self, s):
last = {}
l = 0
ans = 0
for r, ch in enumerate(s):
if ch in last and last[ch] >= l:
l = last[ch] + 1
last[ch] = r
ans = max(ans, r - l + 1)
return ans
- 小坑:只有重复字符位置在当前窗口内,才更新
l。
76 最小覆盖子串¶
- 题目:在
s中找最短子串,要求包含t的所有字符和次数。 - 思路:右指针扩张直到覆盖,覆盖后左指针尽量收缩,同时记录最短答案。
- 标准答案:
from collections import Counter, defaultdict
class Solution:
def minWindow(self, s, t):
need = Counter(t)
window = defaultdict(int)
valid = 0
l = 0
best_len = float('inf')
best_l = 0
for r, ch in enumerate(s):
window[ch] += 1
if ch in need and window[ch] == need[ch]:
valid += 1
while valid == len(need):
if r - l + 1 < best_len:
best_len = r - l + 1
best_l = l
left = s[l]
if left in need and window[left] == need[left]:
valid -= 1
window[left] -= 1
l += 1
if best_len == float('inf'):
return ''
return s[best_l:best_l + best_len]
- 小坑:
valid统计的是满足次数要求的字符种类数,不是字符总数。
239 滑动窗口最大值¶
- 题目:给数组和窗口大小
k,返回每个长度为k的窗口中的最大值。 - 思路:单调队列保存下标,队头永远是当前窗口最大值下标。
- 标准答案:
from collections import deque
class Solution:
def maxSlidingWindow(self, nums, k):
q = deque()
ans = []
for i, x in enumerate(nums):
while q and nums[q[-1]] <= x:
q.pop()
q.append(i)
if q[0] <= i - k:
q.popleft()
if i >= k - 1:
ans.append(nums[q[0]])
return ans
- 小坑:队列里放下标,不放值;这样才能判断是否滑出窗口。
438 找到字符串中所有字母异位词¶
- 题目:在
s中找所有长度等于p、字符组成和p一样的子串起点。 - 思路:固定长度窗口。窗口长度超过
len(p)时移出最左字符;窗口计数等于p的计数时记录起点。 - 标准答案:
from collections import Counter
class Solution:
def findAnagrams(self, s, p):
need = Counter(p)
window = Counter()
ans = []
m = len(p)
for r, ch in enumerate(s):
window[ch] += 1
if r >= m:
left = s[r - m]
window[left] -= 1
if window[left] == 0:
del window[left]
if window == need:
ans.append(r - m + 1)
return ans
- 小坑:固定窗口长度是
len(p);删除计数为 0 的字符,方便比较两个 Counter。