此题难度为HARD!

解题思路 💡
这道题是经典的 滑动窗口(双指针) 问题,核心是通过左右指针动态调整窗口大小,在 O (n) 时间复杂度内找到包含 t 所有字符的最短子串。
-
统计需求 :用数组记录 t 中每个字符的出现次数(
need),并统计需要满足的不同字符数量(required)。 -
扩展窗口 :右指针向右移动,将字符加入当前窗口,更新窗口内字符计数(
window),当窗口满足所有字符需求时,尝试收缩左指针。 -
收缩窗口:左指针向右移动,尽可能缩小窗口,同时保持窗口仍满足所有字符需求,记录最小窗口的起始位置和长度。
-
结果返回:遍历结束后,若存在有效窗口则返回最短子串,否则返回空串。
public class Solution {
public String minWindow(String s, String t) {
// 边界条件处理
if (s == null || t == null || s.length() == 0 || t.length() == 0 || s.length() < t.length()) {
return "";
}// 统计t中字符的需求次数和需要满足的不同字符数 int[] need = new int[128]; // 覆盖所有ASCII英文字符 int required = 0; for (char c : t.toCharArray()) { if (need[c] == 0) { required++; // 新增一个需要满足的字符 } need[c]++; } int[] window = new int[128]; // 记录当前窗口内字符的出现次数 int left = 0, right = 0; // 左右指针 int valid = 0; // 当前窗口中满足need的字符数 int minLen = Integer.MAX_VALUE; // 最小窗口长度 int start = 0; // 最小窗口的起始索引 while (right < s.length()) { char c = s.charAt(right); if (need[c] > 0) { // 仅处理t中需要的字符 window[c]++; // 当窗口中该字符的数量达到需求时,valid+1 if (window[c] == need[c]) { valid++; } } right++; // 右指针扩展窗口 // 当窗口满足所有字符需求时,尝试收缩左指针 while (valid == required) { // 更新最小窗口的长度和起始位置 if (right - left < minLen) { minLen = right - left; start = left; } // 移动左指针,收缩窗口 char d = s.charAt(left); if (need[d] > 0) { // 如果该字符的窗口计数刚好等于需求,收缩后会不满足,valid-1 if (window[d] == need[d]) { valid--; } window[d]--; } left++; } } // 返回结果:若minLen未更新,说明无有效窗口,返回空串 return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen); }}

复杂度分析 📊
- 时间复杂度:O (n),n 为 s 的长度。每个字符最多被左右指针各访问一次,无嵌套循环。
- 空间复杂度:O (1),使用的数组大小固定为 128,与输入规模无关。
