原题指路
至少有 K 个重复字符的最长子串
题目描述
给你一个字符串 s
和一个整数 k
,请你找出 s
中的最长子串, 要求该子串中的每一字符出现次数都不少于 k
。返回这一子串的长度。
解题思路
这道题有别于一般的“滑动窗口”的题目,因为这道题窗口的维护条件需要人为添加一项,即窗口中的字符种类数。
虽然这看起来很复杂,但是由于这题的数据范围限制在小写字母集之内,所以可以直接枚举1-26种字母即可。
移动边界时窗口需维护的变量有:
- 窗口内的字符种类数
tot
; - 窗口内出现次数小于
k
次的字符的数量less
。
时间复杂度:
O
(
N
⋅
∣
Σ
∣
+
∣
Σ
∣
2
)
O(N \cdot |\Sigma| + |\Sigma|^2)
O(N⋅∣Σ∣+∣Σ∣2)
空间复杂度:
O
(
∣
Σ
∣
)
O(|\Sigma|)
O(∣Σ∣)
∣
Σ
∣
=
26
|\Sigma|=26
∣Σ∣=26是字母的个数。
代码
class Solution
{
public:
int longestSubstring(string s, int k)
{
int ret = 0,n = s.length();
for (int t = 1; t <= 26; t++)
{
int l = 0, tot = 0, less = 0;
vector<int> cnt(26, 0);
for(int r=0;r<n;r++)
{
cnt[s[r] - 'a']++;
if (cnt[s[r] - 'a'] == 1)//该字母首次出现
{
tot++;
less++;
}
if (cnt[s[r] - 'a'] == k)//该字母出现次数k次
less--;
while (tot > t)
{
cnt[s[l] - 'a']--;
if (cnt[s[l] - 'a'] == k - 1)//该字符出现次数不足k次
less++;
if (!cnt[s[l] - 'a'])//该字母不在窗口内出现
{
tot--;
less--;
}
l++;
}
if (!less)//窗口内字符串满足题设
ret = max(ret, r - l + 1);
}
}
return ret;
}
};