76. 最小覆盖子串

题目描述

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

注意:

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

输入输出

1
2
3
4
5
6
7
8
9
10
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"

输入:s = "a", t = "a"
输出:"a"

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

基本思路

太难 直接看官方题解视频吧

java实现

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
class Solution {
public String minWindow(String s, String t) {
int sLen = s.length();
int tLen = t.length();
if(sLen == 0 || tLen == 0 || sLen < tLen) return "";

char[] charArrayS = s.toCharArray();
char[] charArrayT = t.toCharArray();

// ascii('z') = 122; 128正好是2的次方
int[] winFreq = new int[128];
int[] tFreq = new int[128];
for(char c:charArrayT){
tFreq[c]++;
}

int distance = 0;
int minLen = sLen + 1;
int begin = 0;
int left = 0, right = 0;
while(right < sLen){
if(tFreq[charArrayS[right]] == 0){
right++;
continue;
}
if(winFreq[charArrayS[right]] < tFreq[charArrayS[right]]){
distance++;
}
winFreq[charArrayS[right]]++;
right++;

while(distance == tLen){
if(right - left < minLen){
minLen = right - left;
begin = left;
}
if(tFreq[charArrayS[left]] == 0){
left++;
continue;
}
if(winFreq[charArrayS[left]] == tFreq[charArrayS[left]]){
distance--;
}
winFreq[charArrayS[left]]--;
left++;
}
}
if(minLen == sLen + 1){
return "";
}
return s.substring(begin, begin + minLen);
}
}