240918-Leetcode76 最小覆盖字串

48 阅读3分钟

请朋友们多多指正

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

注意:

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

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

1.思路

int res为最终结果,即最小覆盖字串长度
int begin为最终结果起始位置
char[] base = new char[128]
char[] cur = new char[128] int hitSize == t.length ? 为是窗口字串否包含t的条件

在s中找符合t的子串,明显可以想到用可收缩的滑动窗口法解决

1)怎么确定当前窗口是否包含t,建立一个char[] base = new char[128],遍历t,每个字符出现一次在对应位置+1,再建立一个动态数组cur和hitSize分别表示滑动过程中的字母组合和符合t的总个数,int hitSize == t.length时候即窗口符合包含t的字串,接下来需要把窗口收缩到最小

2)外层循环中右指针不断右移添加元素直到hitSize符合条件,然后内循环左移左指针直到破坏hitSize== t.length 条件(内循环再不破坏hitSize== t.length 条件时候每次都要更新res和begin),此时就记录了本次循环固定右指针后的最小覆盖字串

2.初版(YOLO)

public String minWindow(String s, String t) {
    //判断边界,窗口大小最小也是t.length()
    if (s.length() < t.length()) {
        return "";
    }
    int minWindowLength = Integer.MAX_VALUE;
    int minWindowBegin = 0;
    int left = 0;
    int right = 0;
    char[] base = new char[128];
    char[] tmp = new char[128];
    int hitSize = 0;

    for (int i = 0; i < t.length(); i++) {
        base[t.charAt(i)]++;
    }

    //左闭右开
    while(right < s.length()){
        //只看在t中的元素
        if (base[s.charAt(right)] > 0){
            //因为可能出现tmp[s.charAt(right)] >= base[s.charAt(right)]的情况,这时候hitSize不再增加
            if (tmp[s.charAt(right)] < base[s.charAt(right)]) {
                hitSize++;
            }
            tmp[s.charAt(right)]++;
        }
        if (hitSize == t.length()){
            while(hitSize == t.length() && left <= right){
                //每次进入循环都要最小覆盖字串
                minWindowBegin = minWindowLength > (right - left + 1) ? left : minWindowBegin;
                minWindowLength = minWindowLength > (right - left + 1) ? (right - left + 1) : minWindowLength;
                //收缩左边界,只看在t中的元素
                if(base[s.charAt(left)] != 0){
                    //因为可能出现tmp[s.charAt(right)] >= base[s.charAt(right)]的情况,这时候hitSize不再减少
                    if (tmp[s.charAt(left)] == base[s.charAt(left)])
                        hitSize--;
                    tmp[s.charAt(left)]--;
                }
                left++;
            }
        }
        right++;
    }
    return minWindowLength == Integer.MAX_VALUE ? "" : s.substring(minWindowBegin, minWindowBegin + minWindowLength);
}

liweiwei的题解

可以看到li用的是左闭右开区间,其他地方差不太多

public class Solution {

    public String minWindow(String s, String t) {
        int[] window = new int[128];
        int[] pattern = new int[128];

        final int A = 'A';

        for (Character c : t.toCharArray()) {
            pattern[c - A]++;
        }
        int distance = 0;

        for (int i = 0; i < 128; i++) {
            if (pattern[i] > 0) {
                distance++;
            }
        }

        int sLen = s.length();
        int start = 0;
        int left = 0;
        int right = 0;
        int match = 0;
        int minLen = sLen + 1;

        while (right < sLen) {
            Character curChar = s.charAt(right);
            if (pattern[curChar - A] > 0) {
                window[curChar - A]++;

                if (window[curChar - A] == pattern[curChar - A]) {
                    match++;
                }
            }

            right++;

            while (match == distance) {
                if (right - left < minLen) {
                    start = left;
                    minLen = right - left;
                }

                // 考虑左边界向右边走
                Character leftChar = s.charAt(left);
                if (pattern[leftChar - A] > 0) {
                    window[leftChar - A]--;

                    if (window[leftChar - A] < pattern[leftChar - A]) {
                        match--;
                    }
                }
                left++;
            }
        }
        return minLen == sLen + 1 ? "" : s.substring(start, start + minLen);
    }
}

作者:liweiwei1419
链接:https://leetcode.cn/leetbook/read/learning-algorithms-with-leetcode/x1vsvd/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。