已开启
最小覆盖子串-湖北工业大学-朱志强-徐承志 #147
aiyeyeyeyeye创建于 2025年6月13日
最小覆盖子串-湖北工业大学-朱志强-徐承志 #147
已开启
共 3 个文件变更+90-0
| @@ -0,0 +1,26 @@ | |||
| 1 | +给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。 | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | +注意: | ||
| 6 | + | ||
| 7 | +对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 | ||
| 8 | +如果 s 中存在这样的子串,我们保证它是唯一的答案。 | ||
| 9 | + | ||
| 10 | + | ||
| 11 | +示例 1: | ||
| 12 | + | ||
| 13 | +输入:s = "ADOBECODEBANC", t = "ABC" | ||
| 14 | +输出:"BANC" | ||
| 15 | +解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。 | ||
| 16 | +示例 2: | ||
| 17 | + | ||
| 18 | +输入:s = "a", t = "a" | ||
| 19 | +输出:"a" | ||
| 20 | +解释:整个字符串 s 是最小覆盖子串。 | ||
| 21 | +示例 3: | ||
| 22 | + | ||
| 23 | +输入: s = "a", t = "aa" | ||
| 24 | +输出: "" | ||
| 25 | +解释: t 中两个字符 'a' 均应包含在 s 的子串中, | ||
| 26 | +因此没有符合条件的子字符串,返回空字符串。 | ||
| @@ -0,0 +1,64 @@ | |||
| 1 | +import java.util.HashMap; | ||
| 2 | +import java.util.Map; | ||
| 3 | + | ||
| 4 | +class Solution { | ||
| 5 | + public String minWindow(String s, String t) { | ||
| 6 | + if (s == null || t == null || s.length() == 0 || t.length() == 0 || s.length() < t.length()) { | ||
| 7 | + return ""; | ||
| 8 | + } | ||
| 9 | + | ||
| 10 | + // 统计 t 中字符出现次数 | ||
| 11 | + Map<Character, Integer> targetMap = new HashMap<>(); | ||
| 12 | + for (char c : t.toCharArray()) { | ||
| 13 | + targetMap.put(c, targetMap.getOrDefault(c, 0) + 1); | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + int required = targetMap.size(); // 需要匹配的字符种类数 | ||
| 17 | + int formed = 0; // 当前窗口中已匹配的字符种类数 | ||
| 18 | + | ||
| 19 | + // 滑动窗口指针 | ||
| 20 | + int left = 0; | ||
| 21 | + int right = 0; | ||
| 22 | + int x=0; | ||
| 23 | + | ||
| 24 | + // 记录最小窗口的信息 | ||
| 25 | + int minLen = Integer.MAX_VALUE; | ||
| 26 | + int minLeft = 0; | ||
| 27 | + | ||
| 28 | + // 统计窗口中字符出现次数 | ||
| 29 | + Map<Character, Integer> windowMap = new HashMap<>(); | ||
| 30 | + | ||
| 31 | + while (right < s.length()) { | ||
| 32 | + char c = s.charAt(right); | ||
| 33 | + windowMap.put(c, windowMap.getOrDefault(c, 0) + 1); | ||
| 34 | + | ||
| 35 | + // 如果当前字符在 t 中,并且窗口中的数量达到了 t 中的数量 | ||
| 36 | + if (targetMap.containsKey(c) && windowMap.get(c).intValue() == targetMap.get(c).intValue()) { | ||
| 37 | + formed++; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + // 尝试收缩左边界 | ||
| 41 | + while (left <= right && formed == required) { | ||
| 42 | + c = s.charAt(left); | ||
| 43 | + | ||
| 44 | + // 更新最小窗口 | ||
| 45 | + if (right - left + 1 < minLen) { | ||
| 46 | + minLen = right - left + 1; | ||
| 47 | + minLeft = left; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + // 左边界移动,更新窗口统计 | ||
| 51 | + windowMap.put(c, windowMap.get(c) - 1); | ||
| 52 | + if (targetMap.containsKey(c) && windowMap.get(c) < targetMap.get(c)) { | ||
| 53 | + formed--; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + left++; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + right++; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + return minLen == Integer.MAX_VALUE ? "" : s.substring(minLeft, minLeft + minLen); | ||
| 63 | + } | ||
| 64 | +} | ||