76. Minimum Window Substring
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).
For example,
S = "ADOBECODEBANC"
T = "ABC"
Minimum window is "BANC"
.
Note:
If there is no such window in S that covers all characters in T, return the empty string ""
.
If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.
题意:从给定字符串S中寻找包含给定字符串T中所有字母的最小子串。
既然是寻找最小子串,遍历字符串S不可避免,在遍历S中每一个字符时,我们需判断该字符是否为T中所含字符,考虑到字符存在重复的可能,在遍历S时还需判断所包含T中存在的字符的出现次数,鉴于此,我采用了“哈希表”来记录T中所包含的字符及其数量,如此可以极大程度的简化判断,具体操作为:
1、由于给定字符串只包含大小写字母,其ASCII范围为[65,90],[97,122],为避免作差,哈希表长度可设为128,对于T中第i个字符对应哈希表的存储位置下标为:T[i];事实上哈希表的长度可以是57=122-65,但如此一来,T中第i个字符对应哈希表的存储位置下标为:T[i]-'A',可根据空间、时间的重要性选择其一;
2、对字符串T进行一次遍历,便可以通过哈希表记录其包含的字符及其数量;
3、然后我们对字符串S进行遍历,建立一个滑动窗口,首尾指针初始化为begin=end=0,当遍历至第end+1个字符时,如果此时滑动串口[begin, end]第一次包含T中所有字符(包括次数),记录子串长度;
4、此后,逐步压缩首指针begin,并更新最小子串长度,直到该窗口不能完全包含T中字符,停止移动begin,改为移动end;当窗口再一次包含T中所有字符时,重复上述步骤,直到end指向S末尾且begin压缩至不能完全包含T中所有字符为止;
5、最后,将记录的最小窗口的字符串返回即可。
【解法及注释】
class Solution {
public:
string minWindow(string s, string t) {
vector<int> count(60,0);//记录T中所包含字符及数量的哈希表,这个哈希表采用数组建立
vector<bool> flag(60,false);//标记T中所包含字符
int sum=t.size();//t中字符总数
int copyBegin=0;//最小子串首端
int begin=0;//滑动窗口首尾指针
int end=0;
int minsize=s.size()+1;//若出现s不能完全包含t的情况,最小子串不存在,但只要存在其长度必然<=s.size()
for(int i=0;i<t.size();i++)//遍历字符串t,标记其包含字符,记录其数量
{
count[t[i]-'A']++;
flag[t[i]-'A']=true;
}
for(int j=0;j<s.size();j++)//遍历字符串s
{
if(flag[s[j]-'A'])//判断s中字符是否为t中字符,若是,减去相应记录
{
count[s[j]-'A']--;//如果对应值小于零,则说明该字符在s中的数量多于t
if(count[s[j]-'A']>=0)//s中包含的某个字符可能多于t中存在的该字符,一旦记录==0,后续重复不应再考虑
sum--;
}
while(sum==0)//当窗口包含t中所有字符及数量
{
if(end-begin+1<minsize)//记录最小串长和最小串首端
{
minsize=end-begin+1;
copyBegin=begin;
}
if(flag[s[begin]-'A'])//压缩窗口首端begin时,如果出现首端元素为t中字符,则需判断
{
count[s[begin]-'A']++;
if(count[s[begin]-'A']>0)//如果对应值小于零,说明该字符重复过多,无需考虑
sum++; //反之,当前窗口不能完全包含t中字符,while()循环条件不再满足,end后移
}
begin++;//压缩首端
}
end++;
}
if(minsize>s.size())return "";//特殊情况,返回空
else return s.substr(copyBegin,minsize);//返回最小子串
}
};