每日一題,防止癡呆 = =
一、題目大意
給你一個字符串 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);
}
};
如果有問題,歡迎大家指正!!!