题目:

给定一个字符串 s 和一个字符串 t,在字符串 s 中找出包含字符串 t 所有字符的最小子串。要求时间复杂度为 O(n)。

引言:

"最小覆盖子串" 是一个关于字符串处理和滑动窗口的问题。解决这个问题需要对字符串的滑动窗口和字符计数有一定的理解,同时需要找到一种方法来在窗口中找到最小子串。通过解答这个问题,我们可以提升对滑动窗口技巧的考虑,同时也能拓展对字符串处理的思路。

算法思路:

为了找到最小覆盖子串,我们可以使用滑动窗口的方法来进行操作。具体思路如下:

  1. 使用两个指针 leftright 来构建一个滑动窗口,表示字符串 s 中的子串。
  2. 初始化一个字符计数的映射,用于存储字符串 t 中每个字符出现的次数。
  3. 使用变量 count 来表示当前窗口中满足要求的字符数目。对于 count,我们只关心其中的正值。
  4. 移动右指针 right,将窗口扩展,同时更新字符计数映射和 count
  5. count 达到 t 中字符数目时,表示当前窗口满足条件。此时,我们可以尝试收缩左指针 left,找到包含所有字符的最小窗口。
  6. 重复步骤 4 和 5,直到右指针到达字符串末尾。
  7. 在过程中记录满足条件的最小窗口的长度和起始位置。

代码实现:

以下是使用 Java 实现的 "最小覆盖子串" 算法的示例代码:

import java.util.HashMap;
import java.util.Map;

public class MinimumWindowSubstring {
    public String minWindow(String s, String t) {
        Map<Character, Integer> targetCount = new HashMap<>();
        for (char c : t.toCharArray()) {
            targetCount.put(c, targetCount.getOrDefault(c, 0) + 1);
        }
        
        int left = 0;
        int right = 0;
        int minLen = Integer.MAX_VALUE;
        int start = 0;
        int count = t.length();
        while (right < s.length()) {
            char charRight = s.charAt(right);
            if (targetCount.containsKey(charRight)) {
                if (targetCount.get(charRight) > 0) {
                    count--;
                }
                targetCount.put(charRight, targetCount.get(charRight) - 1);
            }
            
            right++;
            
            while (count == 0) {
                if (right - left < minLen) {
                    minLen = right - left;
                    start = left;
                }
                
                char charLeft = s.charAt(left);
                if (targetCount.containsKey(charLeft)) {
                    targetCount.put(charLeft, targetCount.get(charLeft) + 1);
                    if (targetCount.get(charLeft) > 0) {
                        count++;
                    }
                }
                
                left++;
            }
        }
        
        return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
    }
}

算法分析:

  • 时间复杂度:遍历字符串一次,所以时间复杂度为 O(n),其中 n 是字符串 s 的长度。
  • 空间复杂度:使用了一个字符计数映射,所以空间复杂度为 O(k),其中 k 是字符串 t 中不同字符的数目。

示例和测试:

假设给定字符串 s = "ADOBECODEBANC"t = "ABC",根据算法,最小覆盖子串为 "BANC"

我们可以使用以下代码进行测试:

public class Main {
    public static void main(String[] args) {
        MinimumWindowSubstring solution = new MinimumWindowSubstring();
        String s = "ADOBECODEBANC";
        String t = "ABC";
        String minWindow = solution.minWindow(s, t);

        System.out.println("Minimum window substring: " + minWindow);
    }
}

总结:

"最小覆盖子串" 算法题要求在字符串中找到包含目标子串的最小子串,是一个关于滑动窗口和字符串处理的问题。通过实现这个算法,我们可以提升对滑动窗口技巧的考虑,同时也能拓展对字符串处理的思路。这个问题强调了如何使用滑动窗口来找到最小子串。

标签: 编程算法, 编程算法题, 编程算法大全, 编程算法流程, 算法设计与分析, 数据结构与算法, 算法优化, 算法实现, 常见编程算法, 编程算法入门, 编程算法进阶, 编程算法精通