每日一题,防止痴呆 = =
一、题目大意
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-window-substring
二、题目思路以及AC代码
对于这种找子串的题,思路其实也不是很复杂,目前看来无非是双指针的方法或者DP,稍加思考也可以得到答案。
思路
本题的思路就是利用双指针,即 l 和 r,开始都在字符串最左端,当 l 和 r 所构成的子串不包含 t 中的元素时,那么我们可以通过移动 r,来使子串加长,直到包含 t 中的元素,验证其是否是最短的包含 t 的子串;然后由于我们在滑动的时候,可能会经过许多重复的元素,比如t = [A, B, C],s = [A, D, A, B, B, D, C],那么我们在保持 l=0 时,去移动右边界 r 到C的过程中,会经过好几个A和B,那么此时他们都是候选的子串,所以我们要再次移动左边界,来检查这些情况,直到移动左边界导致子串不包含 t 了,再重新移动右边界,如此反复即可。
AC代码
#define INF 2147483647
unordered_map<char, int> t_map;
unordered_map<char, int> w_map;
bool check() {
for (unordered_map<char, int>::iterator it=t_map.begin();it!=t_map.end();it++) {
if (w_map[it->first] >= it->second) continue;
else return false;
}
return true;
}
class Solution {
public:
string minWindow(string s, string t) {
t_map.clear();
w_map.clear();
int t_len = t.length();
for (int i=0;i<t_len;i++) {
t_map[t[i]]++;
}
int l = 0, r = 0;
int s_len = s.length();
int rl = -1, rr = -1;
int rlen = INF;
w_map[s[0]] = 1;
while (l <= r && r < s_len) {
if (check()) {
if (r - l + 1 < rlen) {
rlen = r - l + 1;
rl = l;
rr = r;
}
w_map[s[l]]--;
l++;
}
else {
r++;
if (r >= s_len) break;
w_map[s[r]]++;
}
}
if (rr == -1) return "";
return s.substr(rl, rr - rl + 1);
}
};
如果有问题,欢迎大家指正!!!