题意理解
给定一个字符串T,问在另一个字符串S中包含这个字符串的字符的最小长度子字符串。字符顺序可以颠倒
问题分析
滑动窗口 + hashtable做 (双指针法)
其他
比较字符串是否包含,可以用hashmap或字典(每个字符占一个元素位置),字典的速度比map要快
我的方法耗时太长,这里有O(n)的算法。慢慢看。
看完了。几个优化点
一次循环中,同时处理扩展右下标和缩小左下标。
两个map的比较,我是直接找到了全部的t字符再比较,这个方法是逐步删除了左边不满足的字符来比较。搜索的范围小了很多。
不用把所有合适的都保存下来,再从中找最小的那个,而是每次找到一个新字符串,就更新最小的字符串。
每次都是把字符串取下来,再传入函数和t的map比较,这个方法是设置了子串的长度,如果长度满足就狂缩子串,再更新最小字符串。
for循环用了一个技巧,两个if分别对应不同的实际,一个是扩右侧字符,一个是缩左侧字符,互不干扰。
双指针方法,命令很好,low表示慢指针,指向子串开始,high表示快指针,指向子串结尾。
链接
class Solution {
public:
string minWindow(string s, string t) {
int len = s.size();
int left = 0, right = 0;
string result;
int minSize = INT_MAX;
map<char,int> map_t;
map<char,int> map_s;
for(char a : t) //构造字符串map
map_t[a]++;
map_s[s[0]]++;
int preOK = 0;
while(right < len)
{
//cout << left << '\t' << right << endl;
string curWin =s.substr(left, right - left + 1); //获取当前字符串
//cout << curWin << endl;
if (isContain(map_s, map_t)) //当前字符map是否包含t_map
{
//cout << curWin << " is contained" << endl;
if (left + 1 > right) //如果加一位当前字符串存在
{
if (curWin.size() < minSize) //比最小的字符串还短
{
result = curWin; //更新最短字符串
minSize = curWin.size(); //更新最短字符串大小
//cout << "result " << result << endl;
}
right++; //扩大字符串
map_s[ s[right] ]++; //修改map_s的映射
//cout << "add right " << s[right] << endl;
}
else //当前字符串不存在了
{
preOK = 1; //当前字符串是正确的
map_s[ s[left] ]--; //更新map_s的映射
//cout << "remove left " << s[left] << endl;
left++; //缩小字符串
}
}
else //当前字符串不包含t
{
// cout << curWin << " is not contained" << endl;
if (preOK == 1) //之前设置了OK
{
//minStrs.push_back(s.substr(left - 1, right - left + 2));
string curWin = s.substr(left - 1, right - left + 2); //获取之前的子字符串
if (curWin.size() < minSize) //更新到最小字符串中
{
result = curWin;
minSize = curWin.size();
//cout << "result " << result << endl;
}
preOK = 0; //重置OK
}
right++; //扩大字符串,向后找
map_s[ s[right] ]++; //增加map_s的映射
}
}
return result;
}
bool isContain(map<char, int> map_s, map<char, int> map_t)
{
if (map_s.size() < map_t.size()) //s长度短,肯定不能包含t
return false;
bool flag = true;
for(auto it = map_t.begin(); it != map_t.end(); it ++) //遍历t
{
char tChar = it -> first; //获取字符
int tInt = it -> second; //获取数量
if(map_s[tChar] < tInt) //有一个s的字符数量小于t
{
flag = false; //失败
break;
}
}
return flag;
}
};