题目:
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.
分析:
1、对T建立一个hash表hash_t,hash_t[ch]表示在T中字符ch出现的次数。
2、pBegin和pEnd是S中窗口的起止下标,维护窗口[pBegin, pEnd]的hash表hash_s,
则窗口包含T中所有字符的充要条件是hash_s[ch] >= hash_t[ch]对任意ch成立。
3、流程:
(1)初始化hash_t。
(2)pBegin和pEnd指向S的起始位置,向后移动pEnd同时更新hash_s,直到窗口包含T中所有字符。
(3)pBegin向后移动,更新窗口的位置和大小,直到不再满足包含条件,记录下导致包含条件丢失的字符ch。
(4)pEnd向后移动并更新hash_s,直到再次包含(不再通过遍历并比较hash_s和hash_t来确定是否包含,而是pEnd指向ch)。
(5)重复(3)(4)。
class Solution {
public:
string minWindow(string s, string t) {
int hash_t[256];//用来快速判断一个字符是不是属于t
fill_n(hash_t, 256, 0);
for (auto c : t)
{
hash_t[c]++;
}
int hash_s[256];//用来表示t的hash表
fill_n(hash_s, 256, 0);
//初始化
int pBegin = 0, pEnd = 0;//后移pEnd,使得[pBegin, pEnd]包含t中的所有字符
int sLen = s.length();
while (pEnd < sLen)
{
hash_s[s[pEnd]]++;
//判断[pBegin, pEnd]是否包含t中所有字符
bool isContain = true;
for (int i = 0; i < 256; ++i)
{
if (hash_s[i] < hash_t[i])
{
isContain = false;
break;
}
}
if (isContain)
{
break;
}
++pEnd;
}
//t不是s的子集
if (pEnd == sLen)
{
return "";
}
int win_start = pBegin;
int win_size = pEnd - pBegin + 1;
//pBegin向后收缩更新窗口
while (true)
{
char ch = s[pBegin];
++pBegin;
hash_s[ch]--;//从窗口中删除ch
if (hash_s[ch] < hash_t[ch]) //删除ch后窗口不能contain了
{
bool found = false;
for (pEnd++; pEnd < sLen; pEnd++)//pEnd向后查找ch,使得可以重新contain
{
char c = s[pEnd];
hash_s[c]++;
if (c == ch)
{
found = true;
break;
}
}
if (!found)
{
break;//再也不能contain了,返回吧
}
}
else //pBegin的收缩没有影响,更新win
{
//找到了,重新contain
int new_win_size = pEnd - pBegin + 1;
if (new_win_size < win_size)
{
win_size = new_win_size;
win_start = pBegin;
}
}
}
return s.substr(win_start, win_size);
}
};