可以解决的问题
-
嵌套循环问题
-
子串问题:最小覆盖子串,长度最小的子数组
-
常见题目
- 无重复字符的最长子串
- 最小覆盖子串
- 串联所有单词的子串
- 至多包含两个不同字符的最长子串
- 长度最小的子数组
- 滑动窗口最大值
- 字符串的排列
- 最小窗口子序列
滑动窗口框架套路
滑动窗口的大致逻辑框架,伪代码如下:
int left =0,right = 0;
string res = s;
while(right < s.size()) {
window.add(s[right]);
right++;
// 如果符合要求,移动 left 缩⼩窗⼝
while (window 符合要求) {
// 如果这个窗⼝的⼦串更短,则更新 res
res = minLen(res, window);
window.remove(s[left]);
left++;
}
}
return res;
基本流程
- 首先呢,就是获取原字符串的长度。
- 接着维护一个窗口(数组、哈希、队列)
- 窗口一步一步向右扩展
- 窗口在向右扩展滑动过程,需要判断左边是否需要缩减
- 最后比较更新答案
算法思路
- 1、我们在字符串 S 中使⽤双指针中的左右指针技巧,初始化 left = right = 0,把索引闭区间 [left, right] 称为⼀个「窗⼝」。
- 2、我们先不断地增加 right 指针扩⼤窗⼝ [left, right],直到窗⼝中的字符串 符合要求(包含了 T 中的所有字符)。
- 3、此时,我们停⽌增加 right,转⽽不断增加 left 指针缩⼩窗⼝ [left, right],直到窗⼝中的字符串不再符合要求(不包含 T 中的所有字符了)。 同时,每次增加 left,我们都要更新⼀轮结果。
- 4、重复第 2 和第 3 步,直到 right 到达字符串 S 的尽头。
- 滑动窗⼝技巧 285 这个思路其实也不难,第 2 步相当于在寻找⼀个「可⾏解」,然后第 3 步在 优化这个「可⾏解」,最终找到最优解。左右指针轮流前进,窗⼝⼤⼩增增 减减,窗⼝不断向右滑动。
最小覆盖子串
public String minWindow(String s, String t) {
Map<Character, Integer> winMap = new HashMap<>();
Map<Character, Integer> tMap = new HashMap<>();
for (int i = 0; i < t.length(); i++) {
tMap.put(t.charAt(i), tMap.getOrDefault(t.charAt(i), 0) + 1);
}
int left = 0;
int start = 0;
int right = 0;
int total = 0;
int len = Integer.MAX_VALUE;
while (right < s.length()){
char c = s.charAt(right);
if (tMap.containsKey(c)) {
winMap.put(c, winMap.getOrDefault(c, 0) + 1);
if (winMap.get(c).equals(tMap.get(c)) ) {
total++;
}
}
while (total == tMap.size()) {
if (right - left + 1 < len) {
len = right - left + 1;
start = left;
}
char lChar = s.charAt(left++);
if (winMap.containsKey(lChar)) {
if (winMap.get(lChar).equals(tMap.get(lChar))) {
total--;
}
winMap.put(lChar, winMap.get(lChar) - 1);
}
}
right++;
}
return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len);
}