leetcode 76. 最小覆盖子串
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。示例 1:
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
使用两个哈希表,ht存字符串t的字符出现次数。然后遍历字符串s,当某个字符次数还未到t中的次数,则表示该字符是有效字符[可用于覆盖t]。
双指针算加需要指针具有单调性,这样时间复杂度才能为O(n)。
单调性证明:假设[j, i]之间的字符为涵盖t的一段,则当i往后走到i',[j, i']肯定也涵盖了t。此时j也只能往后走,因为要求的是最小子串。
什么时候j可以往后走:当s[j]出现次数大于
t中的次数时,说明即使没有s[j],[j, i]中也至少有了ht[s[j]]个s[j]了,故此时已经不需要j位置字符。
unordered_map<char, int> hs, ht;
string minWindow(string s, string t) {
for (char c : t) ht[c]++;
string ans;
for (int i = 0, j = 0, cnt = 0; i < s.size(); i++) {
hs[s[i]]++;
if (hs[s[i]] <= ht[s[i]]) cnt++;
while (hs[s[j]] > ht[s[j]]) // 不能是>=,因为只有当该字符在hs中冗余了,才能将该字符略过
hs[s[j++]]--;
if (cnt == t.size()) {
if (ans.empty() || i - j + 1 < ans.size())
ans = s.substr(j, i - j + 1);
}
}
return ans;
}
leetcode 3. 无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
指针单调性证明[反证]:假设[j, i]为当前无重复字符最长子串,则当i向后走到i'时,如果此时j往前走,[j', i]肯定包含重复字符,不符题意。故当i往后,j也只能往后走。
什么时候j可以往后走:当新加进来的i字符重复了,此时就需要让j往后走,直到[j, i]无重复字符。
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> hmap;
int ans = 0;
for (int i = 0, j = 0; i < s.size(); i++) {
hmap[s[i]]++;
while (hmap[s[i]] > 1) hmap[s[j++]]--;
ans = max(ans, i - j + 1);
}
return ans;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。