描述
给出两个字符串 s 和 t,要求在 s 中找出最短的包含 t 中所有字符的连续子串。
数据范围:0≤∣S∣,∣T∣≤100000 \le |S|,|T| \le100000≤∣S∣,∣T∣≤10000,保证s和t字符串中仅包含大小写英文字母
要求: 时间复杂度 O(n)O(n)O(n)
例如:
S="XDOYEZODEYXNZ"S ="XDOYEZODEYXNZ"S="XDOYEZODEYXNZ"
T="XYZ"T ="XYZ"T="XYZ"
找出的最短子串为"YXNZ""YXNZ""YXNZ".
注意:
如果 s 中没有包含 t 中所有字符的子串,返回空字符串 “”;
满足条件的子串可能有很多,但是题目保证满足条件的最短的子串唯一。
示例1
输入:
"XDOYEZODEYXNZ","XYZ"
返回值:
"YXNZ"
示例2
输入:
"abcAbA","AA"
返回值:
"AbA"
贴个Java的,参照了某位同志的思路
public class Solution {
// 从头开始检查S,如果是T中的元素,计算如果以该元素作为窗口的第一个元素
public String minWindow(String S, String T) {
if(S == null || S.length() <= 0 || T == null || T.length() <= 0)
return "";
int[] sCount = new int[256];
int[] tCount = new int[256];
for(int i = 0; i < T.length(); i++){
tCount[(int)T.charAt(i)]++;
}
int begin = 0, e_begin = 0;
int end = S.length(), e_end = S.length();
for(int i = 0; i < S.length(); i++){
// 计算以S.charAt(i)开头的最小窗口
// S.charAt(i)不是T中字符,肯定不会是开头
if(tCount[S.charAt(i)] == 0)
continue;
sCount[S.charAt(i)]++;
end = i;
boolean isFind = true;
for(int j = 0; j < 256; j++){
if(sCount[j] < tCount[j]){
isFind = false;
break;
}
}
// 找到了T中所有字符
if(isFind){
// 找到S中包含T中字符的开头
while(begin < S.length()){
int ch = S.charAt(begin);
if(tCount[ch] == 0){
begin++;
continue;
}
// 如果ch出现次数超了,那么开头指针往后
if(sCount[ch] - 1 >= tCount[ch]){
sCount[ch]--;
begin++;
}
else {
break;
}
}
// 更新最小窗口的长度
if(e_end - e_begin > end - begin){
e_end = end;
e_begin = begin;
}
}
}
if(e_end - e_begin >= S.length())
return "";
else
return S.substring(e_begin, e_end + 1);
}
}