# 「每日一题」力扣 76 最小覆盖子串

你好啊,我是蓝莓,今天是每日一题的第 17 天。

题目清单一起刷力扣 (opens new window)

引用力扣题目76 最小覆盖子串 (opens new window)

# 题目描述

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

注意:

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

示例 1:

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

示例 2:

输入:s = "a", t = "a"
输出:"a"
解释:整个字符串 s 是最小覆盖子串。
1
2
3

示例 3:

输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。
1
2
3
4

提示:

  • m == s.length
  • n == t.length
  • 1 <= m, n <= 105
  • st 由英文字母组成

# 实现

思路

  • 使用可变的滑动窗口
  • 这个题目和 438 号题目的题解类似,我们使用 record 记录对于每个字符的需求量
  • 首先使用 t 字符串初始化一开始对每个字符的需求量都是多大
  • 然后遍历 s 字符串,在窗口滑动的过程中分为两种情况
  • (1)当前如果不满足要求的话,那么就扩大窗口的范围,同时维护 record 中的记录
  • (2)如果当前已经满足要求了,那么我们就判断下,当前发现的子串的长度是不是比我们之前找到的子串的长度还要小,如果还要小的话就更新一下子串的起始位置和长度。接着,我们这时候不再扩大窗口了,我们尝试着缩小窗口去寻找更短的满足要求的子串

C++ 代码实现

class Solution {
public:
    string minWindow(string s, string t) {
        if( s.size() < t.size() ) {
            return "";
        }

        int record[256];

        // 数组置空
        memset(record, 0, sizeof(record));

        // 初始化原始需求量
        for( int i = 0 ; i < t.size() ; i++ ) {
            record[t[i]]++;
        }

        // 维护区间 [l...r)
        int l = 0;
        int r = 0;

        // 记录最小覆盖子串的起始位置
        int start = -1;
        // 记录最小覆盖子串的长度
        int minimum_size = INT_MAX;

        while( r <= s.size() ) {
            bool ok = true;

            // 检查是否满足要求
            for( int i = 'A' ; i <= 'z' ; i++ ) {
                if( record[i] > 0 ) {
                    ok = false;
                    break;
                }
            }

            if(ok) {
                // 记录当前的最小字符串
                if( minimum_size > r-l ) {
                    minimum_size = r-l;
                    start = l;
                }

                // 当前已经满足要求 尝试缩小窗口的大小
                record[s[l++]]++;
            } else {
                // 继续扩大窗口
                // 纳入新的元素到 record
                // 对该元素的需求减少 1
                record[s[r++]]--;
            }
        }
        
        if( start == -1 ) {
            return "";
        }

        return s.substr(start, minimum_size);
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
最近更新: 1/6/2025, 4:53:33 PM
「每日一题」力扣 76 最小覆盖子串

酷酷的算法   |