滑动窗口题目的特点如下,经常用于解决字符串的子串问题
- 滑动窗口通过双指针指定窗口的左右边界;
- 通过某种数据结构存储窗口中的元素,数据结构的形式具体问题具体分析,经常是set、dict等;
- 窗口的右边界匀速扩张,而左边界通常是通过某种规律进行向右收缩;
1. 无重复字符的最长子串
-
题目描述
给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度。
示例 1:输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
-
解题思路
- 看到子串,想到可以通过滑动窗口来解决;
- 看到无重复字符想到可以通过set来存储滑动窗口中的元素,可以快速查找当前元素是不是已经在窗口中;
- 滑动窗口从左往右滑动,如果当前元素不在窗口中,直接压入窗口中;如果已经在了,从左边开始弹出元素,直到当前元素不在窗口中,再将元素压入窗口中。这样保证窗口中的元素都是不重复的,那么统计窗口大小的最大值就是最长无重复子串的长度。
-
代码
class Solution: def lengthOfLongestSubstring(self, s: str) -> int: n = len(s) if n == 0: return 0 chars = set() i = 0 res = 0 for j in range(n): if s[j] not in chars: chars.add(s[j]) else: while s[j] in chars: chars.remove(s[i]) i += 1 chars.add(s[j]) # 每完成一次元素更新后,更新最大长度 res = max(res, j - i + 1) return res
2. 找到字符串中所有字母异位词
- 题目描述
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。 - 解题思路
- 本题仍然是寻找子串问题,可以用滑动窗口来解决;
- 看到字母异位词就想到可以通过dict来存储窗口中元素出现的次数;
- 本题中的窗口长度是确定的,利用这个限制条件可以找到符合要求的答案;
- 时间复杂度:
具体的操作可见下面代码中的注释
- 代码
class Solution: def findAnagrams(self, s: str, p: str) -> List[int]: n = len(s) if n == 0: return [] dic_p = {} for char in p: dic_p[char] = dic_p.get(char, 0) + 1 dic_w = {} i = 0 res = [] for j in range(n): if len(dic_w) == 0: i = j if s[j] in dic_p: # 如果当前字符在p中,而且字符在窗口中的数量是符合条件的,那么将该字符加入窗口中 if dic_w.get(s[j], 0) < dic_p[s[j]]: dic_w[s[j]] = dic_w.get(s[j], 0) + 1 else: # 如果加上当前的字符后,当前的字符在窗口中的数量已经超过了p中的数量,那么将窗口左边界右移,直到窗口中的字符数量符合要求 while dic_w.get(s[j], 0) >= dic_p[s[j]]: dic_w[s[i]] -= 1 i += 1 dic_w[s[j]] = dic_w.get(s[j], 0) + 1 # 上面的代码保证了字母的计数是满足要求的,如果此时窗口长度等于p的长度,说明找到了一个符合条件的子串 if j - i + 1 == len(p): res.append(i) else: # 如果出现了一个没有在p中的字符,那么将该窗口清除,重新开始计数 dic_w = {} return res