76. 最小覆盖子串
思路
-
先统计t的字符个数
-
窗口遍历
- left,right指针形成窗口,right从0索引开始滑动
- 统计窗口内t中包含的字符数量
- 当窗口内的字符数量和t中的一样时,则得到了其中一个子串
-
收缩窗口,寻找最小字串
- 先保存当前字串的位置
- 每缩小一个字符,就判断t中是否包含,如果包含,并且该字符在窗口的数量,小于在t中的数量,则缩小之前就是目前的最小子串了
- 继续移动窗口
复杂度分析
- 时间复杂度:
O(N),其中 N 是字符串s的长度。 - 空间复杂度:
O(M),其中 M 是字符串t中不同字符的数量。
代码
class Solution {
public String minWindow(String s, String t) {
if (s == null || t == null || s.length() < t.length()) {
return "";
}
// 统计t的字符数量
Map<Character, Integer> tCountMap = new HashMap<>();
for (char c : t.toCharArray()) {
tCountMap.put(c, tCountMap.getOrDefault(c, 0) + 1);
}
// 窗口内的字符数量
Map<Character, Integer> windowCountMap = new HashMap<>();
// t的字符种类
int tKindCount = tCountMap.size();
// 窗口内从字符种类
int windowKindCount = 0;
// 左指针
int left = 0;
// 最小字串的开始索引
int start = 0;
// 最小字串的长度
int minLen = Integer.MAX_VALUE;
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
// 统计窗口内字串个数
windowCountMap.put(c, windowCountMap.getOrDefault(c, 0) + 1);
// 如果是t中的字符,并且窗口内的数量符合条件,则窗口字符种类+1
if (tCountMap.containsKey(c) && tCountMap.get(c).intValue() == windowCountMap.get(c).intValue()) {
windowKindCount++;
}
// 当字符种类符合条件时,尝试缩小窗口,寻找最小字串
while (windowKindCount == tKindCount) {
// 先记录当前窗口数据
int len = right - left + 1;
if (len < minLen) {
minLen = len;
start = left;
}
char lChar = s.charAt(left);
windowCountMap.put(lChar, windowCountMap.get(lChar) - 1);
// 如果缩小一个字符后,窗口内该字符的数量就和t的不符了,则退出循环,窗口滑动到下一步
if (tCountMap.containsKey(lChar)
&& windowCountMap.get(lChar).intValue() < tCountMap.get(lChar).intValue()) {
windowKindCount--;
}
// 否则继续缩小
left++;
}
}
return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
}
}

浙公网安备 33010602011771号