2020年7月26日 周日 天气晴 【不悲叹过去,不荒废现在,不惧怕未来】
题目简介
LeetCode 76. 最小覆盖子串
这道题应该属于滑动窗口类型里比较经典的了,原理听起来也不难,但是真正动手去写代码的时候,就会发现处处都是细节,一不小心就会出错,害我提交了十几次才通过。也可能是我太菜了吧,感觉这种题目应该经常拿出来练练,锻炼自己将思路转化为代码的能力~
滑动窗口
在滑动窗口类型的问题中都会有两个指针。一个用于「延伸」现有窗口的 r 指针,和一个用于「收缩」窗口的 l 指针。在任意时刻,只有一个指针运动,而另一个保持静止。我们在 s 上滑动窗口,通过移动 r 指针不断扩张窗口。当窗口包含 t 全部所需的字符后,如果能收缩,我们就收缩窗口直到得到最小窗口。
判断字符串 s 是否包含 t 可以用数组或者哈希表,这里我使用的是数组。
代码如下(细节真的很多,所以写了比较详细的注释):
class Solution {
public:
string minWindow(string s, string t) {
vector<int> dict(128,0);
int count = 0;
for(char c : t)
{
++dict[c];
}
count = t.length();
int l=0, r=0, start=0, size = INT_MAX;
while(r<s.length())
{
char c = s[r];
if(dict[c]>0)
--count;
--dict[c]; //先把右边的字符加入窗口
if(count==0) //窗口中已经包含所需的全部字符
{
while(l<r && dict[s[l]]<0) //缩减窗口
{
++dict[s[l++]];
} //此时窗口符合要求
if(r-l+1 < size) //更新答案
{
size = r-l+1;
start = l;
}
++dict[s[l]]; //左边界右移之前需要释放dict[s[l]]
++l;
++count;
}
++r;
}
return size==INT_MAX ? "" : s.substr(start, size);
}
};
我们会用 r
扫描一遍 s,也会用 l
扫描一遍 s,最多扫描2遍 s,所以时间复杂度是 O(n),空间复杂度为O(k),k为 s 和 t 中的字符集合,这里 s 和 t 由英文字母组成,所以空间复杂度为 O(1)。
参考文献
https://leetcode-cn.com/problems/minimum-window-substring/solution/tong-su-qie-xiang-xi-de-miao-shu-hua-dong-chuang-k/
https://leetcode-cn.com/problems/minimum-window-substring/solution/zui-xiao-fu-gai-zi-chuan-by-leetcode-solution/