java
class Solution {
Map<Character, Integer> ori = new HashMap<Character, Integer>();
// cnt:当前滑动窗口 [l, r] 里面,收集到的字符数量
Map<Character, Integer> cnt = new HashMap<Character, Integer>();
public String minWindow(String s, String t) {
int tLen = t.length();
for (int i = 0; i < tLen; i++) {
char c = t.charAt(i);
// 存在就+1,不存在默认0再+1
ori.put(c, ori.getOrDefault(c, 0) + 1);
}
// 滑动窗口:初始r=-1,表示窗口里还没有元素
int l = 0, r = -1;
// len:记录满足条件的最小窗口长度;ansL、ansR 记录最终答案的左右下标
int len = Integer.MAX_VALUE, ansL = -1, ansR = -1;
int sLen = s.length();
// 外层循环
while (r < sLen) {
++r;
//收缩左侧边界
if (r < sLen && ori.containsKey(s.charAt(r))) {
cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);
}
while (check() && l <= r) {
// 当前窗口长度比之前记录的更小 → 更新答案
if (r - l + 1 < len) {
len = r - l + 1;
ansL = l;
ansR = l + len; // substring是左闭右开,所以ansR = l+len
}
//缩减左边界 :如果是t需要的字符,cnt计数-1
if (ori.containsKey(s.charAt(l))) {
cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1);
}
++l;
}
}
// ansL=-1 说明从头到尾没有找到合法窗口,返回空串;否则截取子串
return ansL == -1 ? "" : s.substring(ansL, ansR);
}
public boolean check() {
//获取 ori 的迭代器,用来遍历 t 里【所有要求的字符】
Iterator iter = ori.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Character key = (Character) entry.getKey();
Integer val = (Integer) entry.getValue();
// 窗口里该字符数量不够,直接返回false,不满足条件
if (cnt.getOrDefault(key, 0) < val) {
return false;
}
}
return true;
}
}

缩减左边界时:移除后不应该即时就要检查移除后是否还符合要求吗
这个疑问抓得非常准!先说结论:
✅ 确实是移除之后立刻就会检查,但是不是写在减 cnt 这一行的后面,而是靠 while 循环的条件,下一轮循环开头去 check
java
return ansL == -1 ? "" : s.substring(ansL, ansR);
等价于:

注意:
