给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC" 输出: "BANC"
说明:
- 如果 S 中不存这样的子串,则返回空字符串
""
。 - 如果 S 中存在这样的子串,我们保证它是唯一的答案
1. 注意到题目的关键:"所有字母的最小子串",也就是说两个串都只能是字母。
2. 于是,可以开辟一个大小为64的数组,来存放数组中字母的频率(Frequency)。准确的说,
通过字母的ASCII码作为数组的索引,开辟空间的大小为26+6+26=58:26个大写字母,26个小写字母,
还有中间的6个非字母 A~Z[65~90] 非字母[91~96] a~z[97~122]
3. 滑动窗口的使用:分三种情况来移动窗口:(这里令当前窗口的左右边界分别为l,r,窗口的大小为winSize=r-l+1)
1) 当winSize < t.size() r++; 也就是窗口右边界向右移动
2) 当winSize == t.size() :
2.1) 当窗口中的字符已经符合要求了,直接返回return,已经找到了
2.2) 否则r++,窗口右边界向右移动
3) 当winSize > t.size()
3.1) 当窗口中的字符已经符合要求了,l++,窗口左边界向右移动
3.2) 否则r++,窗口右边界向右移动
#include <iostream>
#include <cstring>
using namespace std;
// 1) 当winSize < t.size() r++; 也就是窗口右边界向右移动
// 2) 当winSize == t.size() :
// 2.1) 当窗口中的字符已经符合要求了,直接返回return,已经找到了
// 2.2) 否则r++,窗口右边界向右移动
// 3) 当winSize > t.size()
// 3.1) 当窗口中的字符已经符合要求了,l++,窗口左边界向右移动
// 3.2) 否则r++,窗口右边界向右移动
string minWindow(string s, string t) {
int l = 0, r = -1;
int sFreq[64] = {0};
int tFreq[64] = {0};
int minl = 0, minr = s.size() + 1;
int flag;
int i;
if(s.size() < t.size()){
return "";
}
for(i = 0; i < t.size(); i++){
tFreq[t[i] - 'A']++;
}
while(true){
if(r - l + 1 < t.size()){
r++;
sFreq[s[r] - 'A']++;
continue;
}
flag = 0;
for(i = 0; i < 64; i++){
if(sFreq[i] < tFreq[i]){
break;
}
}
if(i == 64){
flag = 1;
}
else{
flag = 0;
}
if(r - l + 1 == t.size()){
if(flag == 1){
minl = l;
minr = r;
break;
}
else{
r++;
if(r >= s.size()){
break;
}
sFreq[s[r] - 'A']++;
continue;
}
}
if(r - l + 1 > t.size()){
if(flag == 1){
if(r - l < (minr - minl)){
minr = r;
minl = l;
}
sFreq[s[l] - 'A']--;
l++;
}
else{
r++;
if(r >= s.size()){
break;
}
sFreq[s[r] - 'A']++;
}
}
}
if(minr == s.size() + 1){
return "";
}
return string(s.begin() + minl, s.begin() + minr + 1);
}
int main(){
string s = "AB";
string t = "B";
string re = minWindow(s, t);
cout << re << endl;
return 0;
}