https://leetcode-cn.com/problems/minimum-window-substring/
class Solution {public String minWindow(String s, String t) {// 时间:O(N)// 滑动窗口:枚举 s 中 可能覆盖 t 的子串String resString = "";// 定义一个 HashMap 保存频次HashMap<Character, Integer> frequencyMap = new HashMap<>();// 统计 t 中的字符for (int i = 0; i < t.length(); i++) {char c = t.charAt(i);int count = frequencyMap.getOrDefault(c, 0);frequencyMap.put(c, count + 1);}// 定义左右指针指向滑动窗口的起始、结束位置(左闭右开)int start = 0, end = 1;// 统计子串每个字符出现的频次HashMap<Character, Integer> subStringFrequencyMap = new HashMap<>();while (end <= s.length()) {// end 增加之后,新增的字符char newChar = s.charAt(end - 1);// 新增字符频次加一if (frequencyMap.containsKey(newChar)) {// t 串中有该字符才判断subStringFrequencyMap.put(newChar, subStringFrequencyMap.getOrDefault(newChar, 0) + 1);}// 如果当前子串符合覆盖子串要求,并且比之前的最小子串要短,就替换while (check(frequencyMap, subStringFrequencyMap) && start < end) {if ((resString.equals("") || (end - start) < resString.length())) {resString = s.substring(start, end);}// 对要删除的字符频次减一char removeChar = s.charAt(start);if (frequencyMap.containsKey(removeChar)) {// t 串中有该字符才判断subStringFrequencyMap.put(removeChar, subStringFrequencyMap.getOrDefault(removeChar, 0) - 1);}// 不管是不是最小子串,左指针都需要移动,为了缩小窗口,寻找局部最优解start++;}// 不是覆盖子串,就要扩大窗口,寻找新的子串end++;}return resString;}// 用于检查当前子串是否是一个覆盖 t 的子串private boolean check(HashMap<Character, Integer> tFreq, HashMap<Character, Integer> subFreq) {// 遍历 t 中每个字符的频次,与 subSting 进行比较// 查看 t 中出现的每个字符在 subFreq 中出现的次数,一旦有不相等的情况出现(也不可能大于),就返回 falsefor (Character character : tFreq.keySet()) {if (subFreq.getOrDefault(character, 0) < tFreq.get(character)) {return false;}}return true;}}
class Solution {public String minWindow(String s, String t) {// 时间:O(N),但是实际会比上一个方法快得多// 滑动窗口:枚举 s 中 可能覆盖 t 的子串String resString = "";// 定义一个 HashMap 保存频次HashMap<Character, Integer> frequencyMap = new HashMap<>();// 统计 t 中的字符for (int i = 0; i < t.length(); i++) {char c = t.charAt(i);int count = frequencyMap.getOrDefault(c, 0);frequencyMap.put(c, count + 1);}// 定义左右指针指向滑动窗口的起始、结束位置(左闭右开)int start = 0, end = 1;// 统计子串每个字符出现的频次HashMap<Character, Integer> subStringFrequencyMap = new HashMap<>();// 定义一个"贡献值"变量,统计 t 中的字符在子串中出现了多少int targetCharCount = 0;while (end <= s.length()) {// end 增加之后,新增的字符char newChar = s.charAt(end - 1);// 新增字符频次加一if (frequencyMap.containsKey(newChar)) {// t 串中有该字符才判断subStringFrequencyMap.put(newChar, subStringFrequencyMap.getOrDefault(newChar, 0) + 1);// 频次加一,还要看是否有贡献,如果子串中频次小于 t 中频次,当前字符就有贡献if (subStringFrequencyMap.get(newChar) <= frequencyMap.get(newChar)) {targetCharCount++;}}// 如果当前子串符合覆盖子串要求,即贡献值达到了 t 子串的数值。并且比之前的最小子串要短,就替换while (targetCharCount == t.length() && start < end) {if ((resString.equals("") || (end - start) < resString.length())) {resString = s.substring(start, end);}// 对要删除的字符频次减一char removeChar = s.charAt(start);if (frequencyMap.containsKey(removeChar)) {// t 串中有该字符才判断subStringFrequencyMap.put(removeChar, subStringFrequencyMap.getOrDefault(removeChar, 0) - 1);// 如果子串中的频次不够 t 重的频次,此时相当于减少了一个真正有贡献的 char,贡献值减一if (subStringFrequencyMap.get(removeChar) < frequencyMap.get(removeChar)) {targetCharCount--;}}// 不管是不是最小子串,左指针都需要移动,为了缩小窗口,寻找局部最优解start++;}// 不是覆盖子串,就要扩大窗口,寻找新的子串end++;}return resString;}}
class Solution {
public String minWindow(String s, String t) {
String res = "";
HashMap<Character, Integer> targetMap = new HashMap<>();
for (int i = 0; i < t.length(); i++) {
targetMap.put(t.charAt(i), targetMap.getOrDefault(t.charAt(i), 0) + 1);
}
int start = 0, end = 1;
HashMap<Character, Integer> subStringMap = new HashMap<>();
int subStringCountVal = 0;
while (end <= s.length()) {
// 新增字符的操作
char newChar = s.charAt(end - 1);
if (targetMap.containsKey(newChar)) {
subStringMap.put(newChar, subStringMap.getOrDefault(newChar, 0) + 1);
// 遍历到到字串中到当前char的频次小于或等于目标字串中的频次时,都是有贡献的
// 因为是目标字串中的频次值先加一
if (subStringMap.get(newChar) <= targetMap.get(newChar)) {
subStringCountVal++;
}
}
// 贡献值达到了才会有 start++ 的左缩减操作
while (subStringCountVal == t.length() && start < end) {
if (res.equals("") || (end - start) < res.length()) {
res = s.substring(start, end);
}
char removeChar = s.charAt(start);
if (targetMap.containsKey(removeChar)) {
// 尝试缩减字符
subStringMap.put(removeChar, subStringMap.get(removeChar) - 1);
// 如果字符缩减之后,频次出现问题,贡献值变小
if (subStringMap.get(removeChar) < targetMap.get(removeChar)) {
subStringCountVal--;
}
}
start++;
}
end++;
}
return res;
}
}
