Leetcode 76 最小覆盖子串
问题重述
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = “ADOBECODEBANC”, t = “ABC” 输出:“BANC”
示例 2:
输入:s = “a”, t = “a” 输出:“a”
思路
这一题双指针例题,我们采用滑动窗口的思想。首先左右指针都在最左端,记录下出现了那些字符(我们用bool型数组flag记录),再记录下每一个字母出现了多少次(我们用int型数组chars记录)。
vector<int> chars(128, 0);
vector<bool> flag(128, false);
for (int i = 0; i < t.size(); ++i) {
flag[t[i]] = true; //判断这个字符是不是在t里面出现过,比如字母a出现了就设置flag[a]为真
++chars[t[i]]; //看每一个字母出现了多少次,比如a出现了三次,所以最后chars[a] = 3
}
循环里移动右指针。首先第一个我们要找的串肯定是包含t中出现所有字母。我们可以使用cnt记录,比如字母a是串t中的字符;s中出现一次a,我们将cnt++,并且记录数目的chars[a]减一。
以此类推一直到cnt==t.size的时候。再在一个循环里面移动左指针,如果此时找的串最左侧字符不是t中的字符,显然得到的串满足条件且比之前的串长度少一个,可以继续移动左指针。(所以我们可以使用while循环实现)。一直到最后,找到最短的串。
for (r = 0; r < s.size(); ++r) {
if (flag[s[r]]) {
if (--chars[s[r]] >= 0) {
++cnt;
}//比如这个s[r]是a,所以减了以后chars[a] = 3 - 1 = 2。最后如果cnt==t.size说明这一段已经包含了t的所有字符
while (cnt == t.size()) { // 进入这个while循环的都是已经包含了t中所有的字符,在这里面是选择最短的
if (r - l + 1 < min_size) {
min_l = l;
min_size = r - l + 1;
}//算出如果这个时候小于min_size,说明他比之前找到的短,更新左坐标
if (flag[s[l]] && ++chars[s[l]] > 0) {//flag[s[l]]是说明这个时候左边这个字符是t中的字符
--cnt;//进入这个循环以后,因为你去掉了s中属于t的一个字符,所以cnt不可能和t.size相等,退出while循环,。
}
++l;//不管怎么都左移一位左指针
}
}
}
最终代码:
class Solution {
public:
string minWindow(string s, string t) {
vector<int> chars(128, 0);
vector<bool> flag(128, false);
for (int i = 0; i < t.size(); ++i) {
flag[t[i]] = true; //判断这个字符是不是在t里面出现过,比如字母a出现了就设置flag[a]为真
++chars[t[i]]; //看每一个字母出现了多少次,比如a出现了三次,所以最后chars[a] = 3
}
int cnt = 0, l = 0, r = 0, min_l, min_size = s.size() + 1;
for (r = 0; r < s.size(); ++r) {
if (flag[s[r]]) {
if (--chars[s[r]] >= 0) {
++cnt;
}//比如这个s[r]是a,所以减了以后chars[a] = 3 - 1 = 2。最后如果cnt==t.size说明这一段已经包含了t的所有字符
while (cnt == t.size()) { // 进入这个while循环的都是已经包含了t中所有的字符,在这里面是选择最短的
if (r - l + 1 < min_size) {
min_l = l;
min_size = r - l + 1;
}//算出如果这个时候小于min_size,说明他比之前找到的短,更新左坐标
if (flag[s[l]] && ++chars[s[l]] > 0) {//flag[s[l]]是说明这个时候左边这个字符是t中的字符
--cnt;//进入这个循环以后,因为你去掉了s中属于t的一个字符,所以cnt不可能和t.size相等,退出while循环,。
}
++l;//不管怎么都左移一位左指针
}
}
}
return min_size > s.size()? "": s.substr(min_l, min_size);//所以前面设置的初值min_size要比s。size大
}
};