76. 最小覆盖子串

给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。

示例:

输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”

说明:

如果 S 中不存这样的子串,则返回空字符串 ""。
如果 S 中存在这样的子串,我们保证它是唯一的答案。

方法:滑动窗口法
原理:就是用左右指针l和r在s上面滑动,找到所有的解,然后不断更新记录最小长度的min和起始位置start;
1,用数组map记录T中所有的字母和每个字母出现的个数,数组下标表示该字母ASCII码,数值表示字母出现的个数;
2,从[l,r]从[0,0]位置开始,将r指针代表的字母的ASCII码为下标,将map数组中该下标上的值减一,然后判断该下标上的值是否大于0,如果大于0说明这个字母存在于字符串T中,并且将记录字符个数的count++;继续向右移动r指针,进行重复判断,更新count的值,直到count和字符串T的长度相等;
3,当count和字符串T的长度相等是,说明我们找到了一组解,此时我们需要将l指针拉到正确的位置,只需要判断map数组中,当前l指针上字母的ASCII码索引处的值是否大于0,如果小于0,就一直向右移动,直到其大于0为止,此时[l,r]就是一组正确的解;
4,找到一组正确的解[l,r]之后,r-l就是这个解代表的字符子串的长度,若这个值比当前min的值小,则更新min,并且开始下一轮求解,也就是将l向右移动一位,并且要将count的值减去一,然后把当前l指针处字母的ASCII码为索引的map数组的值加一,也就是要将当前l指针的记录还回去;
5,然后继续上述操作,直到l指针到字符串S的尾只有T字符串的长度,同时要保持r指针最远也只能到字符串S的长度-1处;

注意:说的可能有点儿乱,附上代码,写了详细的注释,可以慢慢捋一捋!

class Solution {
    public String minWindow(String s, String t) {
        //滑动窗口法
        int sl = s.length(), tl = t.length();
        if (sl < tl)
            return "";
        //转化为数组
        char[] sarr = s.toCharArray();
        char[] tarr = t.toCharArray();
        //用数组做映射效率高,下标字母为ASCII的值,数值代表个数
        int[] map = new int[256];
        for (int i = 0; i < tl; i ++)
            map[tarr[i]] ++;//存储个数
        //start记录头位置
        int start = -1;
        //min记录解最小的长度
        int min = sl;
        //定义滑动窗口
        int l = 0, r = 0;
        //定义窗口保存的字符数
        int count = 0;
        //开始滑动窗口,左极限为l + tl == sl;有极限就是sl
        while (l <= sl - tl && r < sl) {
            //判断当前窗口的r指针元素是否存在于t中
            map[sarr[r]] --;//默认初始值为0,为负则表示不存在
            if (map[sarr[r]] >= 0) //存在则将count加一
                count ++;
            //当count == tl时,说明找齐了所有元素
            if (count == tl) {
                //收缩窗口的l指针,将小于0的去除掉
                while (map[sarr[l]] < 0) {
                    map[sarr[l]] ++;//每移动一位就将当前的代表的值加回去
                    l ++;
                }
                //记录位置,较小的值
                if (r - l < min) {
                    start = l;
                    min = r - l;
                }
                //找到一组解之后,则将l指针向右滑动一位,继续下组解的查找
                map[sarr[l]] ++;
                l ++;
                count --;//记录的个数(正确的解)减掉一个              
            }
            //r向右移动
            r ++;
        }
        if (min < sl)
            return s.substring(start,start + min + 1);
        return "";
    }
}

你可能感兴趣的:(修炼,算法,LeetCode)