力扣 Top100 76. 最小覆盖子串

题目来源:https://leetcode-cn.com/problems/minimum-window-substring/

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

思路

使用滑动窗口表示满足题意的 s 的子串

  1. 先使用哈希表存 t 所有字符以及对应个数
  2. 初始时,窗口只包括 s 的首字符,然后开始在 s 上移动窗口,并在移动过程中使用哈希表存下 t 中字符在窗口中的对应个数
  3. 每次移动后,都检查当前窗口右边界对应的字符是否在字符串 t 中,若在,则更新哈希表
  4. 然后检查目前窗口是否包含 t 中所有字符,若已经包含,更新最小窗口。之后右移左边界,缩小窗口。重复这个过程,直至当前窗口不包含 t 中所有字符

代码:

public class MinWindow {
    Map<Character, Integer> charMap;    // 存 t 中字符以及对应个数
    Map<Character, Integer> windowMap;  // 存窗口中字符以及对应个数
    public String minWindow(String s, String t) {
        charMap = new HashMap<>();
        windowMap = new HashMap<>();
        // 统计 t 中字符以及对应个数
        for (int i = 0; i < t.length(); i++) {
            char c = t.charAt(i);
            charMap.put(c, charMap.getOrDefault(c, 0) + 1);
        }
        // 窗口左右边界
        int l = 0;
        int r = 0;
        // 窗口最小长度
        int ans = Integer.MAX_VALUE;
        // 最小窗口对应索引
        int ansL = 0;
        int ansR = 0;
        int n = s.length();
        // 若右边界未越界,则继续
        while (r < n) {
            char c = s.charAt(r);
            // 若 t 包含当前字符,更新窗口对应哈希表
            if (charMap.containsKey(c)) {
                windowMap.put(c, windowMap.getOrDefault(c, 0) + 1);
            }
            // 若窗口中包含 t 的所有字符,且长度大于 0
            while (check() && l <= r) {
                // 更新最小窗口
                int len = r - l + 1;
                if (ans > len) {
                    ans = len;
                    ansL = l;
                    ansR = r + 1;
                }
                // 左边界右移,更新哈希表
                windowMap.put(s.charAt(l), windowMap.getOrDefault(s.charAt(l), 0) - 1);
                l++;
            }
            // 右边界右移
            r++;
        }
        return s.substring(ansL, ansR);
    }
    // 判断窗口是否包含 t 中所有字符
    public boolean check() {
        for (Map.Entry<Character, Integer> entry : charMap.entrySet()) {
            char c = entry.getKey();
            int count = entry.getValue();
            if (count > windowMap.getOrDefault(c, 0)) {
                return false;
            }
        }
        return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值