核心解法:滑动窗口 + 哈希表
思路(4 步走)
-
用数组 / 哈希表统计 t 中字符的出现次数
-
用左右指针形成滑动窗口
-
右指针一直右移,直到窗口包含 t 所有字符
-
满足条件后,左指针尽量右移,缩小窗口,记录最小窗口
-
两个计数数组
- 用数组比 HashMap 更快
- 128 覆盖所有 ASCII 字符
java
int[] need[128]; // 记录 t 里每个字符需要多少个
int[] window[128]; // 记录当前窗口里每个字符有多少个
- 统计 t 字符数量
比如 t="ABC"need ['A']=1, need ['B']=1, need ['C']=1
java
for (char c : t.toCharArray()) need[c]++;
- 右指针扩张窗口
- 右指针一直走
- 遇到 t 需要的字符,就加入窗口
- 当窗口字符数 = 需要的数量 时,
valid++
java
while (valid == t.length()) {
更新最小窗口
左指针右移
如果移出的是需要的字符,可能导致 valid--
}
- 左指针收缩窗口(最关键)
valid == t.length()→ 窗口已经包含 t 所有字符- 这时尽量移动左指针缩小窗口,寻找更短的满足条件的窗口
java
while (valid == t.length()) {
更新最小窗口
左指针右移
如果移出的是需要的字符,可能导致 valid--
}
- 最后返回结果
java
return minLen == 无穷大 ? "" : s.substring(start, start+minLen)
核心变量总结
need[]:t 需要的字符数量
window[]:当前窗口字符数量
valid:窗口中已经满足数量要求的字符种类数
valid == t.length() → 窗口满足条件
完整代码实现:
java
class Solution {
public String minWindow(String s, String t) {
// 用于统计字符串 t 中每个字符需要出现的次数
int[] need = new int[128];
// 用于统计当前滑动窗口内,各字符的数量
int[] window = new int[128];
// 记录 t 中有多少种【不同的字符】(比如 t="aa" → 只有1种)
int needUnique = 0;
// 第一步:统计 t 中所有字符的需求
for (char c : t.toCharArray()) {
// 第一次遇到这个字符,才增加种类数
if (need[c] == 0) {
needUnique++;
}
need[c]++;
}
// 滑动窗口左右指针
int left = 0, right = 0;
// 记录窗口内已经满足数量要求的【字符种类数】
int valid = 0;
// 记录最小窗口的起始位置和长度
int start = 0;
int minLen = Integer.MAX_VALUE;
// 第二步:移动右指针,扩展窗口
while (right < s.length()) {
// 当前要加入窗口的字符
char c = s.charAt(right);
right++;
// 如果这个字符是 t 中需要的字符
if (need[c] > 0) {
// 窗口中该字符数量 +1
window[c]++;
// 如果当前字符的数量【刚好达到需求】
// 说明这一种字符凑齐了,valid +1
if (window[c] == need[c]) {
valid++;
}
}
// 第三步:当窗口满足条件时(所有字符种类都凑齐了)
// 开始移动左指针,缩小窗口,寻找更短的子串
while (valid == needUnique) {
// 更新最小窗口:如果当前窗口更小,就记录下来
if (right - left < minLen) {
start = left;
minLen = right - left;
}
// 要移出窗口的字符
char d = s.charAt(left);
left++;
// 如果移出的字符是 t 中需要的字符
if (need[d] > 0) {
// 如果移出前,该字符数量刚好满足需求
// 那么移出后就不满足了 → valid -1
if (window[d] == need[d]) {
valid--;
}
// 窗口中该字符数量 -1(真正移出)
window[d]--;
}
}
}
// 最后:如果没有找到合法窗口,返回空字符串
// 否则返回最小窗口子串
return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
}
}