描述
给定一个字符串source和一个目标字符串target,在字符串source中找到包括所有目标字符串字母的子串。
如果在source中没有这样的子串,返回"",如果有多个这样的子串,返回起始位置最小的子串。
说明
在答案的子串中的字母在目标字符串中是否需要具有相同的顺序?
——不需要。
样例
给出source = "ADOBECODEBANC",target = "ABC" 满足要求的解 "BANC"
挑战
要求时间复杂度为O(n)
解题思路:
总体思想就是先扫描一遍找到最后一个元素满足t字符串的,然后从左边向右开始收缩,使得满足t字符串的最少字符串返回。
这题先用Map统计t中每个字符和每个字符出现的次数,key表示字符,value表示字符出现的次数。设置一个变量count,然后去从左到右扫描s字符串,如果s中的字符与Map中的字符相等的话,则Map中的字符的次数减去1,并且 count加1
如果count值等于t字符串的长度,然后用end-begin+1的长度与给定的lenth相比较,如果end-begin+1小于lenth,则len=end-begin+1
然后再用s字符串中的left的元素与map比较(即之前比较过的元素,这一步是为了一个个恢复之前比较过的元素的value值,在right后寻找)
然后将子窗口的左边界向右移,略掉不在T中的字符,如果某个在T中的字符出现的次数大于哈希表中的value,则也可以跳过该字符。
举例:ADOBEC比较过了,去掉A比较DOBECODEBA->BECODEBA->ECODEBA->CODEBA->ODEBANC->.......->BANC
代码如下
class Solution {
public:
string minWindow(string S, string T) {
if (T.size() > S.size()) return "";
string res = "";
int left = 0, count = 0, minLen = S.size() + 1;
unordered_map<char, int> m;
for (int i = 0; i < T.size(); ++i) {
if (m.find(T[i]) != m.end()) ++m[T[i]];//保证当s中某一字符出现的次数大于t中时,只计算第一个,后面相同的都跳过
else m[T[i]] = 1;
}
for (int right = 0; right < S.size(); ++right) {
if (m.find(S[right]) != m.end()) {
--m[S[right]];
if (m[S[right]] >= 0) ++count;
while (count == T.size()) {
if (right - left + 1 < minLen) {
minLen = right - left + 1;
res = S.substr(left, minLen);
}
if (m.find(S[left]) != m.end()) {
++m[S[left]];
if (m[S[left]] > 0) ???? --count;
}
++left;
}
}
}
return res;
}
};