Leetcode76. 最小覆盖子串

这篇博客详细介绍了如何解决LeetCode第76题——最小覆盖子串问题,使用了滑动窗口的策略。通过双指针法,动态维护一个窗口,确保窗口内包含目标字符串所有字符。文章讨论了时间复杂度,并提供了Java代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Leetcode76. 最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

注意:

对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"

示例 2:

输入:s = "a", t = "a"
输出:"a"

示例 3:

输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。

方案:双指针
(滑动窗口) O(n)O(n)O(n)

过程如下:

1、遍历t字符串,用ht哈希表记录t字符串各个字符出现的次数。
在这里插入图片描述
2、定义两个指针jjjiiijjj指针用于收缩窗口,iii指针用于延伸窗口,则区间[j,i][j,i][j,i]表示当前滑动窗口。首先让i和j指针都指向字符串s开头,然后枚举整个字符串s ,枚举过程中,不断增加iii使滑动窗口增大,相当于向右扩展滑动窗口。
在这里插入图片描述

3、每次向右扩展滑动窗口一步,将s[i]加入滑动窗口中,而新加入了s[i],相当于滑动窗口维护的字符数加一,即hs[s[i]]++。
在这里插入图片描述
4、对于新加入的字符s[i]s[i]s[i],如果hs[s[i]]<ht[s[i]]hs[s[i]] < ht[s[i]]hs[s[i]]<ht[s[i]],说明当前新加入的字符s[i]是必需的,且还未到达字符串ttt所要求的数量。我们还需要事先定义一个cntcntcnt变量, cntcntcnt维护的是s字符串[j,i][j,i][j,i]区间中满足t字符串的元素的个数,记录相对应字符的总数。新加入的字符s[i]必需,则cnt++。

5、我们向右扩展滑动窗口的同时也不能忘记收缩滑动窗口。因此当hs[s[j]]>ht[s[j]hs[s[j]] > ht[s[j]hs[s[j]]>ht[s[j]时,说明hs哈希表中s[j]s[j]s[j]的数量多于ht哈希表中s[j]的数量,此时我们就需要向右收缩滑动窗口,j++并使hs[s[j]]−−hs[s[j]]--hs[s[j]],即hs[s[j++]]−−hs[s[j ++ ]] --hs[s[j++]]

6、当cnt==t.sizecnt == t.sizecnt==t.size时,说明此时滑动窗口包含符串 t 的全部字符。我们重复上述过程找到最小窗口即为答案。

在这里插入图片描述
时间复杂度分析: 两个指针都严格递增,最多移动 nnn 次,所以总时间复杂度是 O(n)O(n)O(n)

java代码:

public static String minWindow(String s, String t) {
        HashMap<Character, Integer> ht = new HashMap<>();
        HashMap<Character, Integer> hs = new HashMap<>();

        for (int i = 0; i < t.length(); i++) {
            ht.put(t.charAt(i), ht.getOrDefault(s.charAt(i), 0) + 1);
        }
        String ans = "";
        int len = Integer.MAX_VALUE, cnt = 0;
        int j = 0;
        for (int i = 0; i < s.length(); i++) {

            hs.put(s.charAt(i), hs.getOrDefault(s.charAt(i), 0) + 1);
            if (ht.containsKey(s.charAt(i)) && hs.get(s.charAt(i)) <= ht.get(s.charAt(i))) cnt++;

            while (j < i && (!ht.containsKey(s.charAt(j)) || hs.get(s.charAt(j)) > ht.get(s.charAt(j)))) {
                int count = hs.get(s.charAt(j)) - 1;
                hs.put(s.charAt(j), count);
                j++;
            }
            if (cnt == t.length() && i - j + 1 < len) {
                len = i - j + 1;
                ans = s.substring(j, i + 1);
            }
        }
        return ans;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值