滑动窗口
核心是利用双指针维护一个不断变化的区间(维护一个窗口,不断滑动,然后更新答案)。
int left = 0, right = 0; //初始化双指针
while (right < s.size()) {
// 增大窗口
window.add(s[right]);
right++;
// 进行窗口内数据的一系列更新
while (window needs shrink) {
// 缩小窗口
window.remove(s[left]);
left++;
// 进行窗口内数据的一系列更新
}
}
只需要思考以下几个问题:
1、什么时候应该移动 right
扩大窗口?窗口加入字符时,应该更新哪些数据?
2、什么时候窗口应该暂停扩大,开始移动 left
缩小窗口?从窗口移出字符时,应该更新哪些数据?
3、我们要的结果应该在扩大窗口时还是缩小窗口时进行更新?
76. 最小覆盖子串
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
class Solution {
HashMap<Character,Integer> need = new HashMap<>(); //目标字符串所需有的字符
HashMap<Character,Integer> window = new HashMap<>(); //窗口内有的字符
public String minWindow(String s, String t) {
boolean isSatisfied = false; // 窗口内有的字符是否满足
String res = s; //所求字符串
int right = -1, left = 0; //窗口边界
for(char c: t.toCharArray()) need.put(c,need.getOrDefault(c,0)+1); //装配目标字符
while(right < s.length()-1){ //窗口滑动
char c = s.charAt(++right); //窗口右边界延长
window.put(c,window.getOrDefault(c,0)+1);
if(isSatisfied || check()){
isSatisfied = true;
while(true){
//从左边界缩小窗口
char cc = s.charAt(left);
window.put(cc,window.getOrDefault(cc,0)-1);
if(check()){
//可以右移
left++;
}else{
window.put(cc,window.getOrDefault(cc,0)+1); //复原
break; //退出循环
}
}
}
if(isSatisfied && right-left+1 < res.length()) res = s.substring(left, right+1);
}
return isSatisfied == true? res : "";
}
public boolean check(){
for(Map.Entry<Character, Integer> entry: need.entrySet()){
if(window.getOrDefault(entry.getKey(),0) < entry.getValue()){ //窗口中字符数量不满足条件
return false;
}
}
return true;
}