每日一恋 - LeetCode 76. Minimum Window Substring(最小覆盖子串)

题目描述:

Given a string, find the length of the longest substring without repeating characters.

Examples:

Given abcabcbb, the answer is abc, which the length is 3.

Given bbbbb, the answer is b, with the length of 1.

Given pwwkew, the answer is wke, with the length of 3. Note that the answer must be a substring, pwke is a subsequence and not a substring.

给定一个字符串,找出不含有重复字符的最长子串的长度。

示例:

给定 abcabcbb ,没有重复字符的最长子串是 abc ,那么长度就是3。

给定 bbbbb ,最长的子串就是 b ,长度是1。

给定 pwwkew ,最长子串是 wke ,长度是3。请注意答案必须是一个子串,pwke 是 子序列 而不是子串。

解法一(Sliding Window):

首先将 t 中的所有字符出现次数记录到整形数组 hash 中,然后设置一个 counter 代表与 t 中字符的差异度。在 s 右移的过程中,一旦发现当前字符出现在 t 中(hash中对应的值大于 0),就将差异度减一,直到差异度为 0 时,说明找到了一个子串,它匹配所有 t 中的字符。将该子串与之前记录的相比,更新短的子串。之后将窗口左边界右移,判断移出窗口的字符是否在 t 中,如果存在则将差异度加一,否则无须处理。

最后,当右边界到达最右端时,可以结束循环,因为左边界处的元素必定是存在在 t 中的,如果此时还将左边界的元素移出的话,那么最短的子串必定不在剩余的子串中了,所以可以直接结束循环。

public String minWindow(String s, String t) {
    int[] hash = new int[256];
    for (char c : t.toCharArray())
        hash[c] ++;

    int counter = t.length(); // 与t中字符的差异度
    int l = 0;
    int r = 0;
    int min = s.length() + 1;
    String res = "";

    while (r < s.length()) {

        if (hash[s.charAt(r++)] -- > 0)
            counter --;

        while (counter == 0) { // 说明已经找到
            if (min > r-l) { // 找到更短的子串
                min = Math.min(min, r - l);
                res = s.substring(l, r);
            }
            // 说明此字符存在在t中
            if (hash[s.charAt(l++)] ++ == 0) 
                counter ++; // 变为不可用
        }
    }
    return res;
}

通用模板:

很多子串的问题,都是需要满足一些限制条件,因此有大神给出了一套模板,这里借鉴一下,欣赏一下大神优雅的思路。

public int findSubstring(string s){
    vector<int> map(128,0);
    int counter; // 检查子串是否匹配条件
    int begin=0, end=0; // 头尾指针
    int d; //子串的长度

    for() { /* 初始化 hash 数组或者 Map */ }

    while(end<s.size()){

        if(map[s[end++]]-- ?){  /* 更新 counter */ }

        while(/* counter 条件判断 */){ 

             /* 如果找到了更小子串则更新 d */

            // 增加 begin 指针,使得子串再次可用/不可用,也就是需要再向右前进才能找到其他的匹配

            if(map[s[begin++]]++ ?){ /* 更新 counter */ }
        }  

        /* 如果找到了更大子串则更新 d */
    }
    return d;
}

需要注意的是,如果题意取的是最大子串,我们需要再 while 循环的外面进行更新操作;如果取的是最小子串,则要在 while 内层循环里进行更新操作。

关于最大子串的情况,可以参考每日一恋 - LeetCode 3. Longest Substring Without Repeating Characters(无重复字符的最长子串)

参考:

Here is a 10-line template that can solve most ‘substring’ problems
原题链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值