Longest Substring with At Least K Repeating Characters

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.
class Solution {
    public int longestSubstring(String s, int k) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        int max = 0;
        // By providing the required distinct alphabets, we create a condition to reduce
        // our sliding window
        for (int numTargetDistinct = 1; numTargetDistinct <= 26; numTargetDistinct++) {
            // finding logest substring with exactly "numTargetDistinct" unique characters
            // where each character appears atleast K times
            int len = longestDistinct(s, k, numTargetDistinct);
            max = Math.max(max, len);
        }
        return max;
    }

    private int longestDistinct(String s, int K, int numTargetDistinct) {
        Map<Character, Integer> map = new HashMap<>();
        int start = 0, end = 0;
        int uniqueNum = 0;
        int numbersAboveK = 0;
        int max = 0;
        while (end < s.length()) {
            char cEnd = s.charAt(end);
            map.put(cEnd, map.getOrDefault(cEnd, 0) + 1);
            if (map.get(cEnd) == 1)
                uniqueNum++;
            if (map.get(cEnd) == K)
                numbersAboveK++;
            while (uniqueNum > numTargetDistinct) {
                char cStart = s.charAt(start);
                if (map.get(cStart) == K)
                    numbersAboveK--;
                if (map.get(cStart) == 1)
                    uniqueNum--;
                map.put(cStart, map.get(cStart) - 1);
                start++;
            }
            // If all the unique numbers are occuring atleast K times
            if (uniqueNum == numbersAboveK)
                max = Math.max(max, end - start + 1);
            end++;
        }
        return max;
    }
}

Last updated