LeetCode之最小覆盖子串 -- 滑动窗口

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目描述

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

注意:

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。

  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

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

这道题可以用滑动窗口来解决,当窗口中的子串包含t中的所有字符时,计算当前窗口的长度,和原来窗口比较,最后返回最小的窗口中的字符串

1.定义left,right初始值都为0,count表示有效字符的个数,count表示有效字符的种类

定义hash1 表示窗口中的字符串,hash2 表示 t 的字符

首先将 t 中的字符根据键值对放到 hash2 中

移动right,并将right指向的字符放到 hash1 中,放到 hash1之后判断 hash1.get(right) 是否等于 hash2.get(right),如果相等,则是有效字符,count++,不相等则是无效字符

2.直到 count == hash2.size(),此时计算窗口的长度,并与原来长度比较,选较小的,然后将窗口的左右下标存到临时变量里面

3.然后移动left,移动前判断 hash1.get[left] 是否等于 hash2.get(left),如果相等,则证明当前是有效字符,count--,否则count不变。

然后hash.get(left)-- ,left++。

left 一直移动到下一次hash1.get(left) == hash2.get(left)

4.重复步骤1、2、3直到right到达最后

代码

当使用hashMap的接口时,LeetCode上最后一个会通不过,这是因为

java中使用Map时,里面的类型时Integer,因为Integer是对象,所以会缓存频繁使用的数值,范围是-128~127,在这个范围内的数会直接返回缓存值。超过了会new一个对象,所以在get的时候使用 .intValue()即可避免这种情况

hash2.put(t.charAt(i),hash2.getOrDefault(t.charAt(i),0).intValue()+1);

这个问题困扰了我将近4个小时的时间,希望看到这里的小伙伴可以避免出现这个问题

public String minWindow(String s, String t) {
        int left = 0;
        int right = 0;
        int count = 0;//表示当前有效字符
        HashMap<Character,Integer> hash1 = new HashMap<>();
        HashMap<Character,Integer> hash2 = new HashMap<>();
        int len = Integer.MAX_VALUE;//当前最小的窗口
        int tmpl = -1;//暂存最小窗口的left下标


        //将t存放到hash2
        for (int i = 0;i<t.length();i++){
            hash2.put(t.charAt(i),hash2.getOrDefault(t.charAt(i),0).intValue()+1);
        }


        while (right<s.length()){

            char charR = s.charAt(right);
            hash1.put(charR,hash1.getOrDefault(charR,0).intValue()+1);//将right指向的字符存到hash1
            if (hash1.get(charR).intValue() == hash2.getOrDefault(charR,0).intValue()){
                //此时是有效字符
                count++;
            }
            right++;

            //窗口成立时
            while (count == hash2.size()){
                //先更新一下窗口
            if(right-left < len){
                len = right-left;
                tmpl = left;

            }

                //移动left指针,不成立

                if (hash1.get(s.charAt(left)).intValue() == hash2.getOrDefault(s.charAt(left),0).intValue()){
                    count--;
                }
                hash1.put(s.charAt(left),hash1.get(s.charAt(left)).intValue()-1);
                left++;
            }


        }
        //最后返回 tmpl 和 tmpr之间的数
//        char[] str1 = new char[len];
        if (tmpl == -1){
            return new String();
        }

        return s.substring(tmpl,tmpl+len);

}

//大佬的代码
public String minWindow1(String ss, String tt) {
    char[] s = ss.toCharArray();
    char[] t = tt.toCharArray();
    int[] hash1 = new int[128];//用数组模拟哈希表
    int kinds = 0;//标记t中有多少种字符
    for (char ch:t){
        if (hash1[ch]==0){
            kinds++;
        }
        hash1[ch]++;
    }
    int[] hash2 = new int[128];


    int minlen = Integer.MAX_VALUE;
    int begin = -1;

    for (int left = 0,right = 0,count = 0;right<s.length;right++){
        char in = s[right];
        hash2[in]++;
        if (hash2[in]==hash1[in]) count++;

        while (kinds==count){
            if (right-left+1<minlen){
                begin=left;
                minlen = right-left+1;
            }
            char out = s[left];
            left++;
            if (hash2[out]==hash1[out]){
                count--;
            }
            hash2[out]--;

        }

    }
    if (begin == -1){
        return new String();
    }else {
        return ss.substring(begin,begin+minlen);
    }



}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值