Longest Substring With Atleast K Repeating Characters
Problem Description​
Given a string s and an integer k, return the length of the longest substring of s such that the frequency of each character in this substring is greater than or equal to k.
if no such substring exists, return 0.
Examples​
Example 1:
Input: s = "aaabb", k = 3
Output: 3
Explanation: The longest substring is "aaa", as 'a' is repeated 3 times.
Example 2:
Input: s = "ababbc", k = 2
Output: 5
Explanation: The longest substring is "ababb", as 'a' is repeated 2 times and 'b' is repeated 3 times.
Constraints:​
Algorithm​
-
Initialize:
ans: stores the current maximum length of a valid substringfreq: frequency array to store character counts (size 26 for lowercase letters)n: length of the strings
-
Count Character Frequencies:
- Iterate through
sand updatefreq[i]for each characters[i].
- Iterate through
-
Iterate Over Unique Character Counts:
- Use a loop for
curr_uniquefrom 1 to the total number of unique characters (unique) found in step 2.
- Use a loop for
-
Reset for Each Unique Character Count:
- Reset
freqarray to 0 usingmemset(C/C++) or loop assignment (other languages). - Initialize
start,end,cnt(number of unique characters in the window), andcount_k(number of characters with at leastkrepetitions) to 0.
- Reset
-
Sliding Window Technique:
- Use a
whileloop untilendreaches the end of the strings:- Expand Window:
- If
cntis less thancurr_unique:- Increment
freqfor the character atend. - If the character is a new unique character (frequency becomes 1), increment
cnt. - If the character's frequency becomes
k, incrementcount_k. - Increment
end.
- Increment
- If
- Shrink Window:
- If
cntis equal tocurr_unique:- Decrement
freqfor the character atstart. - If the character's frequency becomes
k-1, decrementcount_k. - If the character's frequency becomes 0, decrement
cnt. - Increment
start.
- Decrement
- If
- Expand Window:
- Use a
-
Update Maximum Length:
- If
cntis equal tocurr_uniqueandcount_kis also equal tocurr_unique(all characters in the window have at leastkrepetitions), updateanswith the maximum of the current length (end - start).
- If
-
Return Maximum Length:
- Return the final value of
ans, which represents the length of the longest valid substring.
- Return the final value of
Code Implementations:​
Python:
def longestSubstring(s: str, k: int) -> int:
ans = 0
freq = [0] * 26
n = len(s)
for i in range(n):
freq[ord(s[i]) - ord('a')] += 1
unique = sum(1 for count in freq if count > 0)
for curr_unique in range(1, unique + 1):
memset(freq, 0, sizeof(freq)) # Replace with loop assignment for Python
start = end = cnt = count_k = 0
while end < n:
if cnt <= curr_unique:
ind = ord(s[end]) - ord('a')
if freq[ind] == 0:
cnt += 1
freq[ind] += 1
if freq[ind] == k:
count_k += 1
end += 1
else:
ind = ord(s[start]) - ord('a')
if freq[ind] == k:
count_k -= 1
freq[ind] -= 1
if freq[ind] == 0:
cnt -= 1
start += 1
if cnt == curr_unique and count_k == curr_unique:
ans = max(ans, end - start)
return ans
C++:
#include <vector>
int longestSubstring(std::string s, int k) {
int ans = 0;
std::vector<int> freq(26, 0);
int n = s.size();
// Count character frequencies
for (char c : s) {
freq[c - 'a']++;
}
// Find the number of unique characters
int unique = 0;
for (int count : freq) {
if (count > 0) {
unique++;
}
}
// Iterate over window sizes (1 to the number of unique characters)
for (int curr_unique = 1; curr_unique <= unique; curr_unique++) {
std::fill(freq.begin(), freq.end(), 0); // Reset frequencies for each window size
int start = 0, end = 0, cnt = 0, count_k = 0;
// Use a sliding window approach
while (end < n) {
if (cnt <= curr_unique) {
int ind = s[end] - 'a';
// Expand window
if (freq[ind] == 0) {
cnt++;
}
freq[ind]++;
if (freq[ind] == k) {
count_k++;
}
end++;
} else {
int ind = s[start] - 'a';
// Shrink window
if (freq[ind] == k) {
count_k--;
}
freq[ind]--;
if (freq[ind] == 0) {
cnt--;
}
start++;
}
// Check for valid window
if (cnt == curr_unique && count_k == curr_unique) {
ans = max(ans, end - start);
}
}
}
return ans;
}
Java:
public class Solution {
public int longestSubstring(String s, int k) {
int ans = 0;
int[] freq = new int[26];
int n = s.length();
// Count character frequencies
for (char c : s.toCharArray()) {
freq[c - 'a']++;
}
// Find the number of unique characters
int unique = 0;
for (int count : freq) {
if (count > 0) {
unique++;
}
}
// Iterate over window sizes (1 to the number of unique characters)
for (int curr_unique = 1; curr_unique <= unique; curr_unique++) {
Arrays.fill(freq, 0); // Reset frequencies for each window size
int start = 0, end = 0, cnt = 0, count_k = 0;
// Use a sliding window approach
while (end < n) {
if (cnt <= curr_unique) {
int ind = s.charAt(end) - 'a';
// Expand window
if (freq[ind] == 0) {
cnt++;
}
freq[ind]++;
if (freq[ind] == k) {
count_k++;
}
end++;
} else {
int ind = s.charAt(start) - 'a';
// Shrink window
if (freq[ind] == k) {
count_k--;
}
freq[ind]--;
if (freq[ind] == 0) {
cnt--;
}
start++;
}
// Check for valid window
if (cnt == curr_unique && count_k == curr_unique) {
ans = Math.max(ans, end - start);
}
}
}
return ans;
}
}
JavaScript:
function longestSubstring(s, k) {
let ans = 0;
const freq = new Array(26).fill(0);
const n = s.length;
// Count character frequencies
for (const char of s) {
freq[char.charCodeAt(0) - "a".charCodeAt(0)]++;
}
// Find the number of unique characters
let unique = 0;
for (const count of freq) {
if (count > 0) {
unique++;
}
}
// Iterate over window sizes (1 to the number of unique characters)
for (let curr_unique = 1; curr_unique <= unique; curr_unique++) {
freq.fill(0); // Reset frequencies for each window size
let start = 0,
end = 0,
cnt = 0,
count_k = 0;
// Use a sliding window approach
while (end < n) {
if (cnt <= curr_unique) {
const ind = s.charCodeAt(end) - "a".charCodeAt(0);
// Expand window
if (freq[ind] === 0) {
cnt++;
}
freq[ind]++;
if (freq[ind] === k) {
count_k++;
}
end++;
} else {
const ind = s.charCodeAt(start) - "a".charCodeAt(0);
// Shrink window
if (freq[ind] === k) {
count_k--;
}
freq[ind]--;
if (freq[ind] === 0) {
cnt--;
}
start++;
}
// Check for valid window
if (cnt === curr_unique && count_k === curr_unique) {
ans = Math.max(ans, end - start);
}
}
}
return ans;
}