最小覆盖子串
难度:
标签:
题目描述
English description is not available for the problem. Please switch to Chinese.
代码结果
运行时间: 56 ms, 内存: 16.3 MB
/*
* 思路:
* 使用滑动窗口方法,并结合Java Stream API来进行一些操作。
* 使用Stream API来初始化目标字符频率表,
* 其他逻辑与普通Java实现类似,但不强求使用Stream API处理整个问题。
*/
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class Solution {
public String minWindow(String s, String t) {
if (s == null || t == null || s.length() < t.length()) {
return "";
}
Map<Character, Integer> targetFreq = t.chars().boxed()
.collect(Collectors.toMap(k -> (char) k.intValue(), v -> 1, Integer::sum));
int left = 0, right = 0;
int required = targetFreq.size();
int formed = 0;
Map<Character, Integer> windowCounts = new HashMap<>();
int[] ans = {-1, 0, 0};
while (right < s.length()) {
char c = s.charAt(right);
windowCounts.put(c, windowCounts.getOrDefault(c, 0) + 1);
if (targetFreq.containsKey(c) && windowCounts.get(c).intValue() == targetFreq.get(c).intValue()) {
formed++;
}
while (left <= right && formed == required) {
c = s.charAt(left);
if (ans[0] == -1 || right - left + 1 < ans[0]) {
ans[0] = right - left + 1;
ans[1] = left;
ans[2] = right;
}
windowCounts.put(c, windowCounts.get(c) - 1);
if (targetFreq.containsKey(c) && windowCounts.get(c).intValue() < targetFreq.get(c).intValue()) {
formed--;
}
left++;
}
right++;
}
return ans[0] == -1 ? "" : s.substring(ans[1], ans[2] + 1);
}
}
解释
方法:
这道题使用了滑动窗口和双指针的方法。首先,使用一个字典记录字符串t中每个字符的数量。然后,使用两个指针i和j来表示当前的滑动窗口,初始时都指向s的开头。随着j的向右移动,如果当前字符在t中,就减少字典中对应字符的数量,并且减少计数器cnt的值。当cnt变为0时,说明当前窗口已经包含了t中的所有字符。接着,尝试移动左指针i,直到窗口不再包含t中的所有字符。在这个过程中,记录最小的窗口大小,并更新结果。最后,返回最小覆盖子串。
时间复杂度:
O(n)
空间复杂度:
O(1)
代码细节讲解
🦆
在字典中记录字符串t中每个字符的数量的目的是什么?这与直接遍历s中的字符有何不同?
▷🦆
当cnt变为0时,你提到这意味着滑动窗口已包含t中的所有字符。请问这里的cnt是如何定义和操作的,为什么可以这样用来确定窗口状态?
▷🦆
在尝试移动左指针i以缩小窗口时,你提到要保证窗口仍包含t的所有字符。具体是如何判断窗口不再满足条件,以及如何调整字典中的字符计数的?
▷