问题分析
此问题为滑动窗口问题,问题的难度在于如何有效地滑动窗口。
我这里的策略是使窗口内所有目标字符都位于最右侧。
例如
S = ADOBECODEBANC
,T = ABC
。
当窗口为ADOBECODEB
时我们标记的目标字符应为"A"DOBE"C"ODE"B"
,而不是"A"DO"B"E"C"ODEB
。
窗口继续右滑时,窗口变成了 ADOBECODEBA
,此时窗口两边两个字符相同,我们应该标记右侧字符,并修改窗口的范围。其数据变化过程是这样。
修改字符标记为ADOBE"C"ODE"B""A"
,之后修改窗口的大小(移动左侧边界),将窗口变为"C"ODE"B""A"
。
以此类推我们便可以在O(1)的时间内完成。
完整代码
class Solution {
public:
string minWindow(string s, string t) {
vector<int> charNum(255, 0);
int charCount = t.size();
vector<queue<int>> charQueue(255);
queue<int> border;
unordered_set<int> locNote;
string minWin;
for(int i = 0; i < charCount; i++)
charNum[t[i]]++;
for(int i = 0; i < s.size(); i++){
if(charNum[s[i]] > 0){
charNum[s[i]]--;
charCount--;
border.push(i);
charQueue[s[i]].push(i);
if(charCount == 0)
minWin = s.substr(border.front(), i - border.front() + 1);
}else if(charQueue[s[i]].size() > 0){
char leftBorder = s[border.front()];
charQueue[s[i]].push(i);
locNote.insert(charQueue[s[i]].front());
charQueue[s[i]].pop();
border.push(i);
if(leftBorder == s[i]){
while(locNote.count(border.front()))
border.pop();
if(charCount == 0 && i - border.front() + 1 < minWin.size()){
minWin = s.substr(border.front(), i - border.front() + 1);
}
}
}
}
return minWin;
}
};