Longest Substring with At Least K Repeating Characters
Given a string sksk
if no such substring exists, return 0.
Example 1
Output: 3
Explanation: The longest substring is "aaa", as 'a' is repeated 3 times.
Example 2
Output: 5
Explanation: The longest substring is "ababb", as 'a' is repeated 2 times and 'b' is repeated 3 times.
Constraints:
1 <= s.length <= 104 consists of only lowercase English letters.s1 <= k <= 105
Solution 1 - Using sliding window technique, keep track of longest substring with at least 'k' repeating characters substring
In this approach, we will first capture the characters frequency in input string skk
Let's understand with an example, say the input string is s = "ababbbcadd"k=3
-
First, let's get the character's frequency of input string
into a Map, this is how it looks like.s
-
From the above frequency count, we know for sure, longest substring cannot contain
or'c' , since their count is less than'd' . This also means that these characters will split the input string into two parts, so the longest substring could be either left or right sides.k -
Next, we iterate over each character, and when we reach letter
, we know that this letter cannot be part longest substring, since it did not appeared at least'c' times. Now this occurrence will break the input string into two parts, substring on the left side of letterk and the substring on the right side.'c'
-
Now we have to repeat the above steps on smaller input strings
ands1 = "ababbb" .s2 = "add" -
Let's construct characters frequency of
ands1 .s2
-
Let's continue with the substring
and understand the intution behind the solution, from the characters frequency map ofs1 , we know that characters1 appeared only 2 times, which is less than'a' . So, this cannot be part of longest substring, and it will split the string into parts. There are no characters on the left side of first occurrence of characterk so we can ignore the left side substring, and the substring on right side will be'a' .s3="babbb"
-
Next, construct the characters frequency map of
.s3 = "babbb"
-
From the frequency map of
, we know letters3 cannot be part of longest substring, since it appeared only one time, so letter'a' is going to split the string'a' into two parts. Substring on left side has lesser characters thans3 , so we can ignore that, and the substring on right side will beks4="bbb"
-
Next, construct the characters frequency map of
.s4 = "bbb"
-
This is a valid substring and has each character appeared atleast
times, so the answer isk .3 -
So, what we essentially did is, we split the input string into smaller substrings based on the occurrence of letters that appeared less than
times, and recusrively applied the solution on smaller input strings.k -
Time complexity of this solution is going to be
, where n is the length of input stringO(n) , this is because we are iterating the through input string once and for each substring we capturing character frequency map, since there are 26 characters in lowercase alphabets, that will bes =>O(26) * O(n) .O(n)
Implementation steps:
-
First, we will create a
function that takes input stringhelper ,s starting position of current substring,left ending position of current substring, andright .k -
Next, check if the current substring's length is less than
, i.e.k , this means there are not enough characters in this substring, so we return result asright -left < k .0 -
Next, create an integer array of size 26 and capture characters frequency of input string, since the input can only contain lowercase alphabets, so there can only be 26,
call it
.charsFrequency -
Next, create following 3 variables:
-
: we will use this to store the result, we will initialize this with 0.result -
: we will use this to store the starting index for next substring, we will initialize withstart pointer to start with.left -
: we will use this to check if all the characters in current substring are valid or not, we will initialize this withisValid .true
-
-
Next, iterate from
pointer toi = left pointer, and do the following:right-
Check if the current character at
pointer is appeared lesser thani times, if it is, then recursively call thek function from fromhelper pointer until where this condition occurred. We are essentially checking if the left substring has the valid longest substring or not. Also, updateleft toisValid and update thefalse pointer tostart inorder to skip this letter for the right side substring.i+1
-
Check if the current character at
-
Next, check if
is stillisValid , this means that the entire string is valid and is the longest substring, otherwise recursively calltrue function fromhelper position to the end of stringstart .right
public class LongestSubstringWithAtleastKRepeatingChars {
static int longestWithAtleasetKRepeating(String s, int k) {
return helper(s, 0, s.length(), k);
}
static int helper(String s, int left, int right, int k) {
if(right - left <k) {
return 0;
}
int[] charsFrequency = new int[26];
for(int i=left; i<right; i++) {
charsFrequency[s.charAt(i)-'a']++;
}
boolean isValid = true;
int start =0;
int result =0;
for( int i=left; i<right; i++) {
if(charsFrequency[s.charAt(i)-'a'] <k) {
result = Math.max(result, helper(s, left, i, k));
isValid = false;
start = i+1; // move to next position
}
}
return isValid ? right - left : Math.max(result, helper(s, start, right, k));
}
public static void main(String[] args) {
System.out.println(longestWithAtleasetKRepeating("aaabb", 3));
}
}
Complexity Analysis:
Time complexity: Above code runs in O(n) time, where ns
Space complexity: O(n), space that will be used by recursive calls stack, since there can be n
Above implementations source code can be found at