LeetCode 76. 最小覆盖子串

截止到目前我已经写了 500多道算法题,其中部分已经整理成了pdf文档,目前总共有1000多页(并且还会不断的增加),大家可以免费下载
下载链接https://pan.baidu.com/s/1hjwK0ZeRxYGB8lIkbKuQgQ
提取码:6666

在这里插入图片描述
在这里插入图片描述
视频链接

原理搞懂了,代码就简单多了,但是这里有个关键点,就是怎么记录窗口内的元素,其实很简单,使用一个map就可以,来看下代码。

public String minWindow(String s, String t) {
    //把t中的字符全部放到map中
    Map<Character, Integer> map = new HashMap<>();
    for (char ch : t.toCharArray())
        map.put(ch, map.getOrDefault(ch, 0) + 1);

    int left = 0;//窗口的左边界
    int right = 0;//窗口的右边界

    //满足条件的窗口开始位置
    int strStart = 0;
    //满足条件的窗口的长度
    int windowLength = Integer.MAX_VALUE;

    while (right < s.length()) {
        //记录右指针扫描过的字符
        char rightChar = s.charAt(right);
        //如果右指针扫描的字符存在于map中,就减1
        if (map.containsKey(rightChar))
            map.put(rightChar, map.getOrDefault(rightChar, 0) - 1);
        //记录之后右指针要往右移
        right++;

        //检查窗口是否把t中字符全部覆盖了,如果覆盖了,要移动窗口的左边界
        //找到最小的能全部覆盖的窗口
        while (check(map)) {
            //如果现在窗口比之前保存的还要小,就更新窗口的长度
            //以及窗口的起始位置
            if (right - left < windowLength) {
                windowLength = right - left;
                strStart = left;
            }
            //移除窗口最左边的元素,也就是缩小窗口
            char leftChar = s.charAt(left);
            if (map.containsKey(leftChar))
                map.put(leftChar, map.getOrDefault(leftChar, 0) + 1);
            //左指针往右移
            left++;
        }
    }
    //如果找到合适的窗口就截取,否则就返回空
    if (windowLength != Integer.MAX_VALUE)
        return s.substring(strStart, strStart + windowLength);
    return "";
}

//检查窗口是否把字符串t中的所有字符都覆盖了,如果map中所有
// value的值都不大于0,则表示全部覆盖
private boolean check(Map<Character, Integer> map) {
    for (int value : map.values()) {
        //注意这里的value是可以为负数的,为负数的情况就是,相同的字符右
        // 指针扫描的要比t中的多,比如t是"ABC",窗口中的字符是"ABBC"
        if (value > 0)
            return false;
    }
    return true;
}

上面注释已经写的很详细了,基本上也都能看懂,实际上我们还可以把HashMap换成数组,原理其实都是一样的,来看下代码

public String minWindow(String s, String t) {
    int[] map = new int[128];
    //记录字符串t中每个字符的数量
    for (char ch : t.toCharArray())
        map[ch]++;
    //字符串t的数量
    int count = t.length();
    int left = 0;//窗口的左边界
    int right = 0;//窗口的右边界
    //覆盖t的最小长度
    int windowLength = Integer.MAX_VALUE;
    //覆盖字符串t开始的位置
    int strStart = 0;
    while (right < s.length()) {
        if (map[s.charAt(right++)]-- > 0)
            count--;
        //如果全部覆盖
        while (count == 0) {
            //如果有更小的窗口就记录更小的窗口
            if (right - left < windowLength) {
                windowLength = right - left;
                strStart = left;
            }
            if (map[s.charAt(left++)]++ == 0)
                count++;
        }
    }
    //如果找到合适的窗口就截取,否则就返回空
    if (windowLength != Integer.MAX_VALUE)
        return s.substring(strStart, strStart + windowLength);
    return "";
}

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

数据结构和算法

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值