一、滑动窗口算法的代码框架
/* 滑动窗口算法框架 */
void slidingWindow(string s, string t) {
unordered_map<char, int> need, window;
for (char c : t) need[c]++;
int left = 0, right = 0;
int valid = 0;
while (right < s.size()) {
// c 是将移入窗口的字符
char c = s[right];
// 右移窗口
right++;
// 进行窗口内数据的一系列更新
...
/*** debug 输出的位置 ***/
printf("window: [%d, %d)\n", left, right);
/********************/
// 判断左侧窗口是否要收缩
while (window needs shrink) {
// d 是将移出窗口的字符
char d = s[left];
// 左移窗口
left++;
// 进行窗口内数据的一系列更新
...
}
}
}
二、现在开始套模板,只需要思考以下四个问题:
1、当移动right扩大窗口,即加入字符时,应该更新哪些数据?
2、什么条件下,窗口应该暂停扩大,开始移动left缩小窗口?
3、当移动left缩小窗口,即移出字符时,应该更新哪些数据?
4、我们要的结果应该在扩大窗口时还是缩小窗口时进行更新?
三、例子
滑动窗口算法的思路是这样:
1、我们在字符串S中使用双指针中的左右指针技巧,初始化left = right = 0,把索引左闭右开区间[left, right)称为一个「窗口」。
2、我们先不断地增加right指针扩大窗口[left, right),直到窗口中的字符串符合要求(包含了T中的所有字符)。
3、此时,我们停止增加right,转而不断增加left指针缩小窗口[left, right),直到窗口中的字符串不再符合要求(不包含T中的所有字符了)。同时,每次增加left,我们都要更新一轮结果。
4、重复第 2 和第 3 步,直到right到达字符串S的尽头。这个思路其实也不难,第 2 步相当于在寻找一个「可行解」,然后第 3 步在优化这个「可行解」,最终找到最优解,也就是最短的覆盖子串。左右指针轮流前进,窗口大小增增减减,窗口不断向右滑动,这就是「滑动窗口」这个名字的来历。
下面画图理解一下,needs和window相当于计数器,分别记录T中字符出现次数和「窗口」中的相应字符的出现次数。
初始状态:
增加right,直到窗口[left, right)包含了T中所有字符:
现在开始增加left,缩小窗口[left, right)。
直到窗口中的字符串不再符合要求,left不再继续移动。
之后重复上述过程,先移动right,再移动left…… 直到right指针到达字符串S的末端,算法结束。
代码实现:
class Solution {
public String minWindow(String s, String t) {
Map<Character,Integer> need=new HashMap<>();
Map<Character,Integer> window=new HashMap<>();
for(char c:t.toCharArray()){
need.put(c,need.getOrDefault(c,0)+1);
}
int left=0,right=0;
int valid=0;//表示有效字符的个数
// 记录最小覆盖子串的起始索引及长度
int start = 0, len = Integer.MAX_VALUE;
while(right<s.length()){
char c=s.charAt(right);
right++;
if(need.containsKey(c)){
window.put(c,window.getOrDefault(c,0)+1);
if(window.get(c).equals(need.get(c))){
valid++;
}
}
while(valid==need.size()){
if(right-left<len){
start=left;
len=right-left;
}
char d=s.charAt(left);
left++;
if(need.containsKey(d)){
if(window.get(d).equals(need.get(d))){
valid--;
}
window.put(d,window.getOrDefault(d,0)-1);
}
}
}
return len==Integer.MAX_VALUE?"":s.substring(start,start+len);
}
}