LeetCode 高级 - 最小窗口子字符串

最小窗口子字符串

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

示例:

输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"

说明:

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

分析

核心思想: 首尾双指针,尾指针右移扩张找到包含目标字符的子串,首指针右移收缩使字串最小。

做法:

  1. 预扫描目标字符串 t,哈希表存储出现的字符及其个数
  2. 遍历 源字符串s,遇到 t 中字符,其哈希值减一,直到当前子串包含了所有 t 中的字符,记录该子串,并更新最小子串。
  3. 收缩该子串,首指针右移
    1. 忽略不在 t 中的字符。
    2. 当 子串中出现某字符次数多于 t 中该字符的个数,也可忽略该字符。比如 找到某子串 AACD ,t = ACD,则第一个A也可忽略。
    3. 直到右移至 该子串缺失某字符。如 ACD -> CD
  4. 重复2,直到遍历到s尾

代码

class Solution {
    public String minWindow(String s, String t) {
        if(s.length()<t.length() || s.length()==0 || s ==null || t == null || t.length() == 0)
            return "";

        //模拟哈希表,存储目标字符串的各个字符的个数
        int[] map = new int[255];
        for(int i=0;i<t.length();i++){
            map[t.charAt(i)]++;
        }

        //双指针遍历源字符串s
        int begin = 0,end = 0;
        //最小字符串的起点
        int minBegin = 0;
        //最小字符串的长度
        int res = Integer.MAX_VALUE;
        //用来记录匹配到字符的个数,如果count == t.length()意味着找到一个匹配的字串
        int count = 0;

        //遍历
        while(end < s.length()){
            //这里可理解为缺失字符的个数,==0时则表示 这个字符匹配够了,==1则表示仍需要再匹配一个该字符
            if(map[s.charAt(end)]>0)
                count ++;
            //不需要匹配的字符,其值此时小于0
            map[s.charAt(end)]--;
            //尾指针右移
            end++;
            //匹配到一个字串
            while(count == t.length()){
                //比较字串长度,更新字串信息
                if(end - begin < res){
                    res = end - begin;
                    minBegin = begin;
                }
                //如果首指针对应字符是目标字符之一,则跳出循环
                if(map[s.charAt(begin)] == 0)
                    count--;
                //首指针对应字符的哈希值还原
                map[s.charAt(begin)]++;
                //首指针右移
                begin++;
            }
        }

        return res == Integer.MAX_VALUE? "" :s.substring(minBegin,minBegin + res);
    }
}

猜你喜欢

转载自blog.csdn.net/whdalive/article/details/81132383