string minWindow(string s, string t){ unordered_map<char, int> need, window; for (char c : t) need[c]++;
int left = 0, right = 0; int valid = 0; int n = s.size(); // 记录最小覆盖子串的起始索引及长度 int start = 0, len = n+1; while (right < n) { // c 是将移入窗口的字符 char c = s[right]; // 右移窗口 right++; // 进行窗口内数据的一系列更新 if (need.count(c)) { window[c]++; if (window[c] == need[c]) valid++; }
// 判断左侧窗口是否要收缩 while (valid == need.size()) { // 在这里更新最小覆盖子串 if (right - left < len) { start = left; len = right - left; } // d 是将移出窗口的字符 char d = s[left]; // 左移窗口 left++; // 进行窗口内数据的一系列更新 if (need.count(d)) { if (window[d] == need[d]) valid--; window[d]--; } } } // 返回最小覆盖子串 return len == n+1 ? "" : s.substr(start, len); }
// 判断 s 中是否存在 t 的排列 boolcheckInclusion(string t, string s){ unordered_map<char, int> need, window; for (char c : t) need[c]++;
int left = 0, right = 0; int valid = 0; while (right < s.size()) { char c = s[right]; right++; // 进行窗口内数据的一系列更新 if (need.count(c)) { window[c]++; if (window[c] == need[c]) valid++; }
// 判断左侧窗口是否要收缩 while (right - left >= t.size()) { // 在这里判断是否找到了合法的子串 if (valid == need.size()) returntrue; char d = s[left]; left++; // 进行窗口内数据的一系列更新 if (need.count(d)) { if (window[d] == need[d]) valid--; window[d]--; } } } // 未找到符合条件的子串 returnfalse; }
intlengthOfLongestSubstring(string s) { unordered_map<char, int> m;
int left = 0, right = 0; int res = 0; // 记录结果 while (right < s.size()) { char c = s[right++]; // 进行窗口内数据的一系列更新 m[c]++; // 判断左侧窗口是否要收缩 while (m[c] > 1) { char d = s[left++]; // 进行窗口内数据的一系列更新 m[d]--; } // 在这里更新答案 res = max(res, right - left); } return res; }
当m[c]值大于 1 时,说明窗口中存在重复字符,不符合条件,就该移动left缩小窗口。
要在收缩窗口完成后更新res,因为窗口收缩的 while 条件是存在重复元素,换句话说收缩完成后一定保证窗口中没有重复元素了。
v1.5.2