最小覆盖子串
76. 最小覆盖子串 - 力扣(LeetCode)
Solution
这题思路不难,重点在于优化,如果采用常规做法的话,在判断窗口是否符合条件的时候,就是每次遍历长度为58的win数组来判断,这样做的话复杂度是O(58*m+n),但是实际上这样做是没有必要的,下面就是很重要的优化方法,这个方法适用于很多类似的判断窗口是否符合条件的情况。
维护一个变量less,代表窗口中子串字符的数量小于目标子串字符的个数,当less等于0的时候就说明满足条件。在滑动窗口的过程中维护less变量即可。
这里还获得一个启发就,就是不需要每次都用substr取出窗口字符串,只需要记录头和尾即可,到最后在取截取字符串。
class Solution {
public:// 复杂度(58*m+n)string minWindow1(string s, string t) {int n1 = s.length();int n2 = t.length();vector<int> cnt(58, 0);// unordered_map<char,int>cnt;int res_l = 0, res_r = n1;int flag = 0;for (char c : t)cnt[c - 'A']++;int l = 0;vector<int> win(58, 0);// unordered_map<char,int>win;for (int r = 0; r < n1; ++r) {char cur = s[r] - 'A';win[cur]++;while (check(win, cnt)) {flag = 1;// string temp=s.substr(l,r-l+1);if (r - l < res_r - res_l) {res_r = r;res_l = l;}win[s[l] - 'A']--;l++;}}string res = s.substr(res_l, res_r - res_l + 1);return (flag == 0) ? "" : res;}bool check(vector<int> a, vector<int> b) {for (int i = 0; i < a.size(); ++i) {if (a[i] < b[i])return false;}return true;}// 更优的做法,复杂度O(m+n)// 核心优化的点就在于如何判断当前窗口是否符合条件// 这里用一个变量less来记录窗口子串字符的数量小于目标子串字符的个数,当less等于0的时候就说明满足条件// 在滑动窗口的过程中维护less变量即可string minWindow(string s, string t) {int n1 = s.length();int n2 = s.length();vector<int> cnt(58, 0);int less = 0;for (char c : t) {if (cnt[c - 'A'] == 0)less++;cnt[c - 'A']++;}vector<int> win(58, 0);int l = 0, res_l = 0, res_r = n1, flag = 0;for (int r = 0; r < n1; ++r) {int cur = s[r] - 'A';if (++win[cur] == cnt[cur])less--;while (less == 0) {flag = 1;if (r - l < res_r - res_l) {res_l = l;res_r = r;}int index = s[l] - 'A';if (win[index] == cnt[index])less++;win[index]--;l++;}}string temp = s.substr(res_l, res_r - res_l + 1);return (flag == 1) ? temp : "";}
};