76. 最小覆盖子串(java实现,题解,双指针, 哈希)

题目传送门

吐槽:

首先java的空指针异常的确是思路不够清晰导致的,但是做题方面和c++比起来也太坑了吧。搞明白算法就不容易了,居然还要处理各种java需要的细节。难度倍增。我直接吐血身亡。。。

解题思路:

这道题的意思是让我们找出一个字符串s的某一个子串。这个子串满足的条件是包含另一个字符串t的所有字符。

那问题就转成了将字符串t的所有字符统计起来。看看s的哪个子串能包含这个统计。(当然,子串长度要最小)。

此题的解法是双指针做法 + 哈希表:

  1. 我们先统计出字符串 t 的所有字符出现的个数,这里用哈希表存
  2. 然后我们创建另一个哈希表,去遍历 s 串,代表着 s 的字符出现的对应次数
  3. 声明一个变量 cnt , 用来统计s串遍历到当前有多少个合法字符。
  4. 此时用双指针做法,右指针位置的字符先对应加到哈希表中,比对一下这个字符在两个哈希表的值,如果是 t 串的个数多,那说明这个位置是有用的。cnt 要加一。
  5. 在比对完当前位置是否有用之后。要将前面没有用的都过滤掉,左指针位置的字符假设为k,如果 t 的哈希表统计的k的个数小于 s 的哈希表统计的k的个数。说明 s 表里面有多余的k,那当前位就可以不要了,左指针右移即可。
  6. 重复5的过程直到失败,此时不能继续移动了,如果移动根据上面的说法 s 中k的个数必定不够。
  7. 此时判断是否 cnt 的个数等于 t 的长度,如果等于,说明我们找到一个子串,满足包含 t 的所有字符。
  8. 用一个字符串res来当答案,如果res为空,直接将上面左指针和右指针之间的字符串更新成res,否则看一下找到的子串长度和res谁长,如果res长,就更新掉。

代码实现:

class Solution {
    public String minWindow(String s, String t) {
    	// 用来存s的字符有多少个
        Map<Character, Integer> hs = new HashMap<Character, Integer>();
        // 用来存t的字符有多少个
        Map<Character, Integer> ht = new HashMap<Character, Integer>();
        // 统计一下t的每个字符有多少个
        for (int i = 0; i < t.length(); i ++ ) {
            Integer num = ht.get(t.charAt(i));
            if (num == null) {
                ht.put(t.charAt(i), 1);
            } else {
                ht.put(t.charAt(i), num + 1);
            }
        }
		// 定义答案
        String res = "";
        // 定义合法字符个数:如果s[?]在t中有并且个数还没有达到我们就说这个字符合法
        int cnt = 0;

        for (int i = 0, j = 0; i < s.length(); i ++ ) {
        	// 当前位直接+1
            Integer num = hs.get(s.charAt(i));
            if (num == null) {
                hs.put(s.charAt(i), 1);
            } else {
                hs.put(s.charAt(i), num + 1);
            }
            
            Integer htnum = ht.get(s.charAt(i));
            // 当合法时,合法字符个数加一
            if (htnum != null && hs.get(s.charAt(i)) <= htnum) cnt ++ ;
            // 如果当前位没有用,左指针右移即可
            // 此处就是我为什么要吐槽。。。j < i要写不然空指针
            // 括号要匹配对,不然优先级出问题还是空指针,我裂开来。。!
            while(j < i && (ht.get(s.charAt(j)) == null || (hs.get(s.charAt(j)) != null && hs.get(s.charAt(j)) > ht.get(s.charAt(j))))) {
            	// 记得个数减一,不然遇到这个字符就一直判断为没用。
                hs.put(s.charAt(j), hs.get(s.charAt(j)) - 1);
                j ++ ;
            }

            if (cnt == t.length() && (i - j + 1 < res.length() || res.equals(""))) {
                res = s.substring(j, i + 1);
            }


        }


        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值