【算法设计与分析】最小覆盖字串

       个人主页:五敷有你      

 系列专栏:算法分析与设计

⛺️稳中求进,晒太阳

题目

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

注意:

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

示例 

示例 1:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。

示例 2:

输入:s = "a", t = "a"
输出:"a"
解释:整个字符串 s 是最小覆盖子串。

示例 3:

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

思路 

用哈希表+滑动窗口

算法分析与实现

  1. 初始化变量和数据结构

    • 定义变量 n1n2 分别表示字符串 st 的长度。
    • 初始化空字符串 minStr 用于存储最小子串。
    • 初始化变量 left 为0,表示窗口的左边界。
    • 使用 HashMap 数据结构 map 存储字符串 t 中每个字符及其出现次数。
  2. 统计字符串 t 中字符的出现次数

    • 遍历字符串 t 中的每个字符,将字符及其出现次数存储在 map 中。
  3. 遍历字符串 s 中的字符

    • 使用变量 count 统计当前窗口中包含字符串 t 中字符的数量。
    • 遍历字符串 s 中的字符,如果字符在 t 中,更新 map 中对应字符的出现次数,并根据出现次数是否大于等于零更新 count
    • count 等于 n2 时,表示当前窗口包含了字符串 t 中的所有字符,进入内部的 while 循环。
  4. 滑动窗口

    • while 循环中,首先更新最小子串 minStr,如果当前子串比之前的子串更短或者 minStr 为空,则更新。
    • 然后移动窗口的左边界 left,通过逐步增加左边界的位置,缩小窗口,直到不能满足包含所有字符的条件。
    • 继续遍历字符串 s 中的字符,重复上述步骤,直到遍历完成。
  5. 返回最小子串

    • 返回最终的最小子串 minStr

这个算法通过滑动窗口的方式,优化了暴力搜索的复杂度,使得算法在时间上更为高效

 代码实现

 

class Solution {
    public String minWindow(String s, String t) {
        int n1 = s.length();
        int n2 = t.length();
        String minStr = "";
        int left = 0;
        Map map = new HashMap<>();
        for (int i = 0; i < n2; i++) {
            map.put(t.charAt(i), map.getOrDefault(t.charAt(i), 0) + 1);
        }
        int count = 0;
        for (int j = 0; j < n1; j++) {
            if (map.containsKey(s.charAt(j))) {
                map.put(s.charAt(j), map.get(s.charAt(j)) - 1);
                if (map.get(s.charAt(j)) >= 0) {
                    count++;
                }
                while (count == n2) {
                    if (minStr.equals("") || j - left + 1 < minStr.length()) {
                        minStr = s.substring(left, j + 1);
                    }
                    if (map.containsKey(s.charAt(left))) {
                        map.put(s.charAt(left), map.get(s.charAt(left)) + 1);
                        if (map.get(s.charAt(left)) > 0) {
                            count--;
                        }
                    }
                    left++;
                }
            }
        }
        return minStr;
    }
}

运行结果

时间复杂度为

        其中 n2 为字符串 t 的长度。内部有一个 while 循环,但由于每个字符最多只会进入窗口两次(一次进入,一次出去),整体的时间复杂度仍然是 O(n1),其中 n1 为字符串 s 的长度。

空间复杂度分析

        最坏情况下,map 中可能存储字符串 t 所有不同字符,因此空间复杂度为 O(n2),其中 n2 为字符串 t 的长度。

综合分析:

  • 时间复杂度: O(n1 + n2)
  • 空间复杂度: O(n2)

【算法设计与分析】最小覆盖字串_第1张图片

你可能感兴趣的:(算法分析与设计,算法,leetcode,数据结构,java)