class Solution {
public String minWindow(String s, String t) {
//记录字符串当前s窗口中各字符的数量
HashMap<Character, Integer> hs = new HashMap<>();
//记录字符串t中各字符的数量
HashMap<Character, Integer> ht = new HashMap<>();
//先将ht填好
for(int i = 0; i < t.length(); i ++)
ht.put(t.charAt(i), ht.getOrDefault(t.charAt(i), 0) + 1);
//count记录当前窗口中满足t字符串的字符个数(必需字符),len记录符合条件的字串长度(取最小)
//!!!len不能等与s.length(),因为第4步的判断条件是len > i - j + 1,当s=t时没有输出
int count = 0, len = s.length() + 1;
String ans = "";
//[i, j]为滑动窗口
for(int i = 0, j = 0; i < s.length(); i ++){
//1.窗口右移了,更新hs中s[i]的value
hs.put(s.charAt(i), hs.getOrDefault(s.charAt(i), 0) + 1);
/* 2.ht中有新增的s[i]字符,并且hs中s[i]字符的数量 <= ht中s[i]字符的数量
* 表明窗口右移新增的字符s[i]是必需的,count++
* 注意此处有=号,不是<。原因是第1步已经更新了hs中的值,if中并不是<之后增加hs中的值,此处需要=
*/
if(ht.containsKey(s.charAt(i)) && hs.get(s.charAt(i)) <= ht.get(s.charAt(i)))
count ++;
/* 3.移动窗口左边界,必需满足j < i(左边界 < 右边界)
* 如果字符串t中不包含s[j]字符,直接移动左边界
* 如果hs中s[j]的数量 > ht中s[j]的数量,也可以移动左边界
* 格式为while(a && (b || c))
*/
while(j < i && (!ht.containsKey(s.charAt(j)) || hs.get(s.charAt(j)) > ht.get(s.charAt(j)))){
hs.put(s.charAt(j), hs.get(s.charAt(j)) - 1);
// int tmp = hs.get(s.charAt(j)) - 1;
// hs.put(s.charAt(j), tmp);
j ++;
}
//4.必需字符达到了t的长度(条件满足),且长度比上次记录的小,更新数据
if(count == t.length() && len > i - j + 1){
len = i - j + 1;
ans = s.substring(j, i + 1);
}
}
return ans;
}
}