题目描述
给定一个字符串 s ,找出 至多 包含 k 个不同字符的最长子串 T。
示例1:
输入: s = "eceba", k = 2
输出: 3
解释: 则 T 为 "ece",所以长度为 3。
解题思路
这道题和“LRU缓存机制”有一定关系,都是有序字典的题目。此题可用“滑动窗口”的思路解决,去看第76题的解题模版和思路!(已AC)
参考代码
我的实现(不推荐)
class Solution {
public:
int lengthOfLongestSubstringKDistinct(string str, int k) {
int length = str.length();
if (k <= 0 || length == 0)
return 0;
if (k >= length)
return length;
int maxLen = 0;
map<char, int> umap;
int left = 0, right = 0;
while (right < length) {
umap[str[right]]++;
while (umap.size() <= k) { // 因为是“至多”包含k个不同字符的最长子串,所以是 <=
maxLen = max(maxLen, right - left + 1);
if (umap.size() == k && (right == length - 1 || umap.count(str[right + 1]) == 0)) { // 只有当umap.size() == k时,才去右移left,否则一直右移right扩大子串长度
umap[str[left]]--;
if (umap[str[left]] == 0)
umap.erase(str[left]);
left++;
}
else // 这里的break是关键,开始没写死循环了。
break;
}
right++;
}
return maxLen;
}
};
大佬实现(推荐)
class Solution:
def lengthOfLongestSubstringKDistinct(self, s: str, k: int) -> int:
from collections import defaultdict
lookup = defaultdict(int)
start = 0
end = 0
max_len = 0
counter = 0 # 这是关键!相当于76题处的 matchNum,加了这个参数后会方便很多!
while end < len(s):
if lookup[s[end]] == 0:
counter += 1
lookup[s[end]] += 1
# 注意这里和其它滑动窗口题的区别是,这里是不满足条件时while循环(所以不能一味按模板做题,要具体情况具体分析,灵活~)
while counter > k:
lookup[s[start]] -= 1
if lookup[s[start]] == 0:
counter -= 1
start += 1
max_len = max(max_len, end - start + 1) # counter <= k时,更新 max_len
end += 1
return max_len