76. 最小覆盖子串

image

76. 最小覆盖子串

思路

  1. 先统计t的字符个数

  2. 窗口遍历

    • left,right指针形成窗口,right从0索引开始滑动
    • 统计窗口内t中包含的字符数量
    • 当窗口内的字符数量和t中的一样时,则得到了其中一个子串
  3. 收缩窗口,寻找最小字串

    • 先保存当前字串的位置
    • 每缩小一个字符,就判断t中是否包含,如果包含,并且该字符在窗口的数量,小于在t中的数量,则缩小之前就是目前的最小子串了
    • 继续移动窗口

复杂度分析

  • 时间复杂度:O(N),其中 N 是字符串 s 的长度。
  • 空间复杂度:O(M),其中 M 是字符串 t 中不同字符的数量。

代码

class Solution {
    public String minWindow(String s, String t) {
        if (s == null || t == null || s.length() < t.length()) {
            return "";
        }

        // 统计t的字符数量
        Map<Character, Integer> tCountMap = new HashMap<>();
        for (char c : t.toCharArray()) {
            tCountMap.put(c, tCountMap.getOrDefault(c, 0) + 1);
        }
        // 窗口内的字符数量
        Map<Character, Integer> windowCountMap = new HashMap<>();
        // t的字符种类
        int tKindCount = tCountMap.size();
        // 窗口内从字符种类
        int windowKindCount = 0;
        // 左指针
        int left = 0;
        // 最小字串的开始索引
        int start = 0;
        // 最小字串的长度
        int minLen = Integer.MAX_VALUE;
        for (int right = 0; right < s.length(); right++) {
            char c = s.charAt(right);
            // 统计窗口内字串个数
            windowCountMap.put(c, windowCountMap.getOrDefault(c, 0) + 1);
            // 如果是t中的字符,并且窗口内的数量符合条件,则窗口字符种类+1
            if (tCountMap.containsKey(c) && tCountMap.get(c).intValue() == windowCountMap.get(c).intValue()) {
                windowKindCount++;
            }

            // 当字符种类符合条件时,尝试缩小窗口,寻找最小字串
            while (windowKindCount == tKindCount) {
                // 先记录当前窗口数据
                int len = right - left + 1;
                if (len < minLen) {
                    minLen = len;
                    start = left;
                }
                char lChar = s.charAt(left);
                windowCountMap.put(lChar, windowCountMap.get(lChar) - 1);
                // 如果缩小一个字符后,窗口内该字符的数量就和t的不符了,则退出循环,窗口滑动到下一步
                if (tCountMap.containsKey(lChar) 
                    && windowCountMap.get(lChar).intValue() < tCountMap.get(lChar).intValue()) {
                    windowKindCount--;
                }
                // 否则继续缩小
                left++;
            }
        }
        return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
    }
}
posted @ 2025-08-08 23:52  quanht  阅读(9)  评论(0)    收藏  举报