思路:
- 对于基串,用vector创建一个英文字母表来记录,一共52个字母,字母x每出现一次cnt[x]-1。
- 对于参考串,采用滑动窗口,枚举不同首字母的子串。滑动窗口可用分析:“aabbcd”中找“abc” “(aabbc)d”中含有“abc”,移动首指针 “a(abbc)d”中也含有“abc”,可以发现前一次寻找的最后一个字母c是满足要求所必须的,所以,即使移动了首指针,要使满足要求,c也必须包含,所以尾指针是不需要前移的,因此可以使用滑动窗口。
- 滑动窗口的使用:枚举不同首字母子串,在不同的首字母下,让end尾指针不断右移,并同时使cnt[s[end]]+1,这样当字母x和基串的一样时候,cnt[x]=0。这样直到找到满足要求的子串,停止尾指针的右移。更新最短子串start-end,首指针前移一位,同时cnt[s[star]]-1。
对应的代码和注释
class Solution {
public:
string minWindow(string s, string t) {
vector<int>cnt(58);//A-z字母表
string res;
//用字母表记录基串的字母数
for (int i = 0; i < t.length(); i++)
{
--cnt[t[i] - 'A'];
}
int diff = 0;//用diff记录子串中相对基串不够的字母数
for (int i = 0; i < 58; i++)
{
if (cnt[i] < 0)diff += 1;
}
int high = 0,len=INT_MAX;
//滑动窗口
for (int low = 0; low < s.length(); low++)
{
if (diff == 0) {//移动low指针,需验证更新最短子串
if ((high - low) < len ? 1 : 0)
{
res = s.substr(low, high - low);
len = high - low;
}
}
while (high< s.length()&& diff!=0)
{
//移动high指针 子串进元素
//进元素后,导致子串不足字母少1,diff-1,
++cnt[s[high] - 'A'];
if (cnt[s[high] - 'A'] == 0)
{
diff -= 1;
}
high++;
if (diff == 0) {//找到满足要求的子串,更新最短子串
if ((high-low)<len?1:0)
{
res=s.substr(low,high-low);
len = high - low;
}
break;
}
}
//子串出元素
--cnt[s[low] - 'A'];
//若出元素后,导致子串不足字母多1,diff+1
if (cnt[s[low] - 'A'] == -1)
{
diff += 1;
}
}
return res;
}
};