12.最小覆盖子串【困难】
给定两个字符串 s 和 t 。返回 s 中包含 t 的所有字符的最短子字符串。如果 s 中不存在符合条件的子字符串,则返回空字符串 "" 。
如果 s 中存在多个符合条件的子字符串,返回任意一个。
注意: 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC" 输出:"BANC" 解释:最短子字符串 "BANC" 包含了字符串 t 的所有字符 'A'、'B'、'C'
示例 2:
输入:s = "a", t = "a" 输出:"a"
示例 3:
输入:s = "a", t = "aa" 输出:"" 解释:t 中两个字符 'a' 均应包含在 s 的子串中,因此没有符合条件的子字符串,返回空字符串。
思路:
- 先用哈希表
ori统计字符串t中每个字符的出现次数(这是我们需要满足的目标)。 - 用两个指针
l(左)和r(右)维护一个滑动窗口,窗口范围是[l, r]。 - 右指针
r不断向右扩展,把字符加入窗口(统计到cnt哈希表),直到窗口包含t的所有字符。 - 此时尝试移动左指针
l来缩小窗口,同时检查窗口是否仍满足条件,记录最小的有效窗口。 - 重复步骤 3-4,直到右指针遍历完整个字符串
s。
注意:
check()函数迭代器逐个遍历ori的元素看看cnt中对应元素数量是否一致,全部一致返回true,否则返回false
while (check() && l <= r) {……} 当满足窗口内子串>= t字符串时,才会执行循环 去缩小窗口。
minLen记录当前最小窗口。
View Code
if (r - l + 1 < minLen) {……} 比当前最小窗口小再 进行缩小窗口操作
ansR, ansL 记录的是当前最小窗口的左右边界
1 class Solution { 2 // ori:存储t中每个字符的目标出现次数 3 Map<Character, Integer> ori = new HashMap<Character, Integer>(); 4 // cnt:存储当前滑动窗口中每个字符的出现次数 5 Map<Character, Integer> cnt = new HashMap<Character, Integer>(); 6 7 public String minWindow(String s, String t) { 8 int tLen = t.length(); 9 // 第一步:统计t中每个字符的出现次数,初始化ori 10 for (int i = 0; i < tLen; i++) { 11 char c = t.charAt(i); 12 // getOrDefault:如果key不存在,返回默认值0,然后+1 13 ori.put(c, ori.getOrDefault(c, 0) + 1); 14 } 15 16 // l:左指针 17 int l = 0; 18 int sLen = s.length(); // 单独存储字符串长度,避免复用 19 int minLen = Integer.MAX_VALUE; // 专门记录最短窗口长度,初始为最大值 20 int ansL = -1, ansR = -1; 21 22 // 外层循环:右指针r遍历整个字符串 23 for (int r = 0; r < sLen; r++) { 24 char ss = s.charAt(r); 25 if (ori.containsKey(ss)) { 26 cnt.put(ss, cnt.getOrDefault(ss, 0) + 1); 27 } 28 29 // 缩小当前窗口:找到以当前r为右边界的最短有效窗口 30 while (check() && l <= r) { 31 // 只有当前窗口比历史最短更短时,才更新结果 32 if (r - l + 1 < minLen) { 33 minLen = r - l + 1; // 更新最短窗口长度 34 ansL = l; 35 ansR = l + minLen; // 适配substring左闭右开 36 } 37 38 // 左指针右移,移出窗口字符 39 if (ori.containsKey(s.charAt(l))) { 40 cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1); 41 } 42 l++; 43 } 44 } 45 46 // 最终返回结果:如果没找到有效窗口则返回空串 47 return ansL == -1 ? "" : s.substring(ansL, ansR); 48 } 49 50 // 核心辅助函数:检查当前窗口是否满足t的字符要求 51 public boolean check() { 52 Iterator iter = ori.entrySet().iterator(); 53 while (iter.hasNext()) { 54 Map.Entry entry = (Map.Entry) iter.next(); 55 Character key = (Character) entry.getKey(); 56 Integer val = (Integer) entry.getValue(); 57 if (cnt.getOrDefault(key, 0) < val) { 58 return false; 59 } 60 } 61 return true; 62 } 63 }
os: 难……啊………………救命………………

浙公网安备 33010602011771号