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).
Example:
Input: S = "ADOBECODEBANC", T = "ABC"
Output: "BANC"
Note:
- If there is no such window in S that covers all characters in T, return the empty string “”.
- If there is such window, you are guaranteed that there will always be only one unique minimum window in S.
Solution
这个题目使用滑动窗口来解。复杂度是 O ( n ) O(n) O(n)。
class Solution {
public:
string minWindow(string s, string t) {
//记录t中字符出现的次数。
int ch[256] = {0};
//记录运行过程中从pstart到pend之间字符出现的次数。
int ch_count[256] = {0};
//记录每个在t中出现的字符在s中的位置,因为使用滑动窗口,所以每次选择的是最先被记录的那个,采用队列。
queue<int> positions;
int t_length = t.size();
for (int i = 0; i < t_length; ++i) {
++ch[t[i]];
}
int s_length = s.size();
/***
* pstart 滑动窗口的起始位置
* pend滑动窗口的结束位置
* count用来衡量在pstart和pend之间是否包含了t中的全部字符包括字符的出现次数是否大于等于t中次数。
* prev记录pend上次的位置,避免重复。
*/
int pstart = -1, pend = 0, count = 0, pstart_backup = 0, pend_backup = 0, prev = -1;
while (pend < s_length) {
if (ch[s[pend]]) {
/***
* 如果在pstart和pend之间出现的该字符出现的次数小于t中该字符出现的次数
* 则count++,因为在后面会给该字符出现次数也加1。
*/
if (ch_count[s[pend]] < ch[s[pend]]) {
count = count + 1;
}
//定位第一次出现的位置。
if (pstart == -1) {
pstart = pend;
}
//避免重复计数
if (pend != prev) {
positions.push(pend);
++ch_count[s[pend]];
prev = pend;
}
//从pstart到pend时一个符合条件的子串
if (count == t_length) {
//计算长度,如果需要就备份
if(pend - pstart + 1 < pend_backup - pstart_backup || pend_backup - pstart_backup == 0) {
pstart_backup = pstart;
pend_backup = pend + 1;
}
/***
* 移动pstart之前,移除对s[pstart]的计数
* 此时如果s[pstart]的计数小于ch[s[pstart]],则count-1,pend后移
*/
if ((--ch_count[s[pstart]]) < ch[s[pstart]]) {
count = count - 1;
pend = pend + 1;
}
positions.pop();
pstart = positions.front();
} else {
pend = pend + 1;
}
} else {
pend = pend + 1;
}
}
return s.substr(pstart_backup, pend_backup - pstart_backup);
}
};