查阅更多的题解,请点击
Problem
395. Longest Substring with At Least K Repeating Characters(Medium)
Find the length of the longest substring T of a given string (consists of lowercase letters only) such that every character in T appears no less than k times.
Example 1:
Input:
s = "aaabb", k = 3
Output:
3
The longest substring is "aaa", as 'a' is repeated 3 times.
Example 2:
Input:
s = "ababbc", k = 2
Output:
5
The longest substring is "ababb", as 'a' is repeated 2 times and 'b' is repeated 3 times.
Solution
设字符串s的长度为n
O(n^2) time
解决该问题最朴素的想法就是枚举所有的情况:枚举前n-k个字符作为substring的开头的所有情况。
在枚举过程中,需要判断当前枚举的子串是否满足每个字符都出现至少k次,由于最多只有26个字符,则可以用一个整数,数的一个二进制位来对应一个字符是否出现至少k次,比如,整数最低的二进制代表字符a,该位为0,则代表:
- 子串中未出现字符a
- 子串中出现字符a且a至少出现了k次
该算法在最坏情况下是O(n^2) time
class Solution
{
public:
int longestSubstring(string s, int k)
{
if (s.size() < k)
return 0;
int n = s.size();
int res = 0;
for (int begin = 0; begin + k <= n;)
{
vector<int> count(26, 0);
int isAllMatch = 0;
int end = begin;
int maxEnd = begin;
for (; end < n; ++end)
{
int cur = s[end] - 'a';
count[cur]++;
if (count[cur] >= k)
isAllMatch &= (~(1 << cur));
else
isAllMatch |= (1 << cur);
//catch a substring which meets the condition.
if (isAllMatch == 0)
{
res = max(end - begin + 1, res);
maxEnd = end;
}
}
begin = maxEnd + 1;
}
return res;
}
};
O(n) time
观察原问题是否可以reduce,满足题意的子串中每个字符都至少出现k次,则原字符串中出现次数少于k次的字符,一定不会出现在解中,我们可以依据这些出现次数少于k次的字符对原字符串进行划分,在子问题中求解(若字符串不存在出现次数少于k的字符,则该字符串就是所求解)
子问题显然不多于26个,最坏情况下子问题求解是O(n) time的,所以原问题是O(n) time的
class Solution
{
private:
int getLongestSubstring(string &s, int begin, int end, int k)
{
vector<int> count(26, 0);
for (int i = begin; i < end; ++i)
{
count[s[i] - 'a']++;
}
int res = 0;
for (int i = begin; i < end;)
{
//find the first char which appears no less than k
while (i < end && count[s[i] - 'a'] < k)
i++;
if (i == end)
break;
int j = i;
//find the first char which appears less than k
while (j < end && count[s[j] - 'a'] >= k)
j++;
//find an substring which matches the condiation.
if (i == begin && j == end)
return end - begin;
res = max(res, getLongestSubstring(s, i, j, k));
i = j + 1;
}
return res;
}
public:
int longestSubstring(string s, int k)
{
if (s.size() < k)
return 0;
return getLongestSubstring(s, 0, s.size(), k);
}
};