WELCOME TO Pluto134340小行星

清风湿润,茶烟轻扬。

12.最小覆盖子串【困难】

LCR 017. 最小覆盖子串

给定两个字符串 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记录当前最小窗口。
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 }
View Code

 

os: 难……啊………………救命………………

posted @ 2026-01-15 11:17  Pluto134340  阅读(3)  评论(0)    收藏  举报