「力扣」第 76 题:最小覆盖子串(滑动窗口)

  • 只关心字符是否出现,并不关心字符出现的次数。

滑动窗口的定义:表示滑动窗口内部包含了 t 中的字符个数,这里借用了编辑距离的概念。

方法一:定义距离

Java 代码:

public class Solution {
    
    

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

        final int A = 'A';

        char[] tCharArray = t.toCharArray();
        for (Character c : tCharArray) {
    
    
            pattern[c - A]++;
        }

        // 表示滑动窗口内部包含了 t 中的字符个数,这里借用了编辑距离的概念
        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;

        char[] sCharArray = s.toCharArray();

        // 滑动窗口定义:[left, right) 是包含 T 的子串

        while (right < sLen) {
    
    
            Character curChar = sCharArray[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 = sCharArray[left];
                if (pattern[leftChar - A] > 0) {
    
    
                    window[leftChar - A]--;

                    if (window[leftChar - A] < pattern[leftChar - A]) {
    
    
                        match--;
                    }
                }
                left++;
            }
        }

        if (minLen == sLen + 1) {
    
    
            return "";
        }
        return s.substring(start, start + minLen);
    }

    public static void main(String[] args) {
    
    
        Solution solution = new Solution();
        String S = "ADOBECODEBANC";
        String T = "ABC";
        String minWindow = solution.minWindow(S, T);
        System.out.println(minWindow);
    }
}

方法二:定义字符数是否一样

滑动窗口方法是暴力解法的优化,窗口在滑动的过程中,不会错过最优解。

  • 右边界可以前进的条件:还没有包含 T 的所有字母;
  • 左边界可以前进的条件:已经包含了 T 的所有字母;
  • 滑动窗口定义:[left, right) 内包含了 T 的所有字母,长度为 right - left

Java 代码:

public class Solution {
    
    

    /**
     * 首先建立文本串和模式串的概念
     *
     * @param s 文本串
     * @param t 模式串
     * @return
     */
    public String minWindow(String s, String t) {
    
    
        int[] pattern = new int[128];
        int[] window = new int[128];
        for (char ct : t.toCharArray()) {
    
    
            pattern[ct]++;
        }
        // t 中有多少种字符,重复字符只记录一次
        int tCount = 0;
        // 滑动窗口内有多少种字符在 t 中
        int sCount = 0;
        // 首先计算滑动窗口内的元素和 pattern 的差距
        for (int i = 0; i < 128; i++) {
    
    
            if (pattern[i] > 0) {
    
    
                tCount++;
            }
        }
        
        int sLen = s.length();
        int start = 0;
        int left = 0;
        int right = 0;
        int minLen = sLen + 1;

        char[] sCharArray = s.toCharArray();
        while (right < sLen) {
    
    
            if (pattern[sCharArray[right]] > 0) {
    
    
                window[sCharArray[right]]++;
                if (window[sCharArray[right]] == pattern[sCharArray[right]]) {
    
    
                    sCount++;
                }
            }

            right++;
            while (sCount == tCount) {
    
    
                // 想清楚为什么在这里取最小值,此时 [left, right) 内正好包含 T 的所有字母,这一段要写在 left 移动之前
                if (right - left < minLen) {
    
    
                    minLen = right - left;
                    start = left;
                }
                if (pattern[s.charAt(left)] > 0) {
    
    
                    window[s.charAt(left)]--;
                    if (window[s.charAt(left)] < pattern[s.charAt(left)]) {
    
    
                        sCount--;
                    }
                }
                left++;
            }
        }
        if (minLen == sLen + 1) {
    
    
            return "";
        }
        return s.substring(start, start + minLen);
    }
}

猜你喜欢

转载自blog.csdn.net/lw_power/article/details/105779785