HomeLeetcode395. Longest Substring with At Least K Repeating Characters - Leetcode Solutions

395. Longest Substring with At Least K Repeating Characters – Leetcode Solutions

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.

Solution in Python

Thought Process:

  1. Character Frequency:
    • If a character appears fewer than kkk times in the string, it cannot be part of any valid substring. Thus, we can split the string around such characters.
  2. Divide and Conquer:
    • Split the string into substrings based on characters that appear fewer than k.
    • Recursively check each substring to find the longest valid substring.
  3. Base Case:
    • If the string length is less than k, no substring can meet the condition, so return 0.
    • If all characters in the string occur at least k times, the string itself is the longest valid substring.
  4. Efficiency:
    • By splitting the string into smaller parts and skipping invalid characters, we avoid unnecessary computations.
Python
class Solution:
    def longestSubstring(self, s: str, k: int) -> int:
        # Helper function to determine the length of the longest valid substring
        def helper(s: str, k: int) -> int:
            # Base case: If the string length is less than k, return 0
            if len(s) < k:
                return 0
            
            # Count the frequency of each character in the string
            freq = {}
            for char in s:
                freq[char] = freq.get(char, 0) + 1
            
            # Identify characters that appear fewer than k times
            for char, count in freq.items():
                if count < k:
                    # Split the string around this character and recursively check the parts
                    return max(helper(substring, k) for substring in s.split(char))
            
            # If all characters occur at least k times, the entire string is valid
            return len(s)
        
        # Call the helper function with the input string
        return helper(s, k)

Explanation of the Code:

  1. Base Case:
    • If the string’s length is less than k, return 0 because no substring can satisfy the condition.
  2. Frequency Count:
    • Count the occurrences of each character using a dictionary (freq).
  3. Split Condition:
    • If a character appears fewer than k times, split the string around this character using s.split(char). Recursively calculate the longest valid substring for each part.
  4. Valid Substring:
    • If all characters in the string have frequencies greater than or equal to k, the string itself is valid, and we return its length.
  5. Recursive Search:
    • Use recursion to handle each substring split and find the maximum length among all valid substrings.

Solution in C++

C++
class Solution {
public:
    int longestSubstring(std::string s, int k) {
        // Helper function for divide and conquer
        return helper(s, 0, s.size(), k);
    }

private:
    // Divide and conquer method to find the longest valid substring
    int helper(const std::string& s, int start, int end, int k) {
        // Base case: If the substring length is less than k, return 0
        if (end - start < k) {
            return 0;
        }

        // Frequency map to count the occurrences of each character in the substring
        std::unordered_map<char, int> freq;
        for (int i = start; i < end; ++i) {
            ++freq[s[i]];
        }

        // Check for characters with a frequency less than k
        for (int i = start; i < end; ++i) {
            if (freq[s[i]] < k) {
                // If a character has a frequency less than k, split the string at this character
                int left = helper(s, start, i, k);    // Recur for the left part
                int right = helper(s, i + 1, end, k); // Recur for the right part
                return std::max(left, right);
            }
        }

        // If all characters in the substring have a frequency >= k, return its length
        return end - start;
    }
};

Solution in Javascript

JavaScript
var longestSubstring = function(s, k) {
    // Helper function to check the longest substring with a specific number of unique characters
    const longestSubstringWithNUniqueChars = (s, k, uniqueTarget) => {
        let start = 0, end = 0, maxLen = 0;
        let charFrequency = {}; // Tracks frequency of characters in the current window
        let uniqueCount = 0; // Number of unique characters in the current window
        let charsWithEnoughFrequency = 0; // Number of characters in the window with frequency >= k
        
        while (end < s.length) {
            // Expand the window by including s[end]
            const charEnd = s[end];
            if (!charFrequency[charEnd]) {
                charFrequency[charEnd] = 0;
                uniqueCount++;
            }
            charFrequency[charEnd]++;
            if (charFrequency[charEnd] === k) {
                charsWithEnoughFrequency++;
            }
            end++;
            
            // Shrink the window until uniqueCount <= uniqueTarget
            while (uniqueCount > uniqueTarget) {
                const charStart = s[start];
                if (charFrequency[charStart] === k) {
                    charsWithEnoughFrequency--;
                }
                charFrequency[charStart]--;
                if (charFrequency[charStart] === 0) {
                    uniqueCount--;
                    delete charFrequency[charStart];
                }
                start++;
            }
            
            // Update the maximum length if all unique characters in the window have frequency >= k
            if (uniqueCount === uniqueTarget && uniqueCount === charsWithEnoughFrequency) {
                maxLen = Math.max(maxLen, end - start);
            }
        }
        
        return maxLen;
    };
    
    let maxLen = 0;
    const uniqueCharCount = new Set(s).size; // Total unique characters in the string
    
    // Try for every possible number of unique characters in the substring
    for (let currentUnique = 1; currentUnique <= uniqueCharCount; currentUnique++) {
        maxLen = Math.max(maxLen, longestSubstringWithNUniqueChars(s, k, currentUnique));
    }
    
    return maxLen;
};

Solution in Java

Java
class Solution {
    public int longestSubstring(String s, int k) {
        // Helper function that uses divide and conquer
        return longestSubstringHelper(s, 0, s.length(), k);
    }
    
    // Function to find the longest substring in a given range [start, end)
    private int longestSubstringHelper(String s, int start, int end, int k) {
        // Base case: if the length of the substring is less than k, return 0
        if (end - start < k) return 0;
        
        // Step 1: Count the frequency of each character in the current substring
        int[] freq = new int[26]; // 26 for each lowercase letter
        for (int i = start; i < end; i++) {
            freq[s.charAt(i) - 'a']++;
        }
        
        // Step 2: Iterate over the substring and find characters that don't meet the frequency requirement
        for (int i = start; i < end; i++) {
            if (freq[s.charAt(i) - 'a'] < k) {
                // This character doesn't appear at least k times
                // Use this character as a split point
                int left = longestSubstringHelper(s, start, i, k);
                int right = longestSubstringHelper(s, i + 1, end, k);
                // Return the maximum length found in the left and right partitions
                return Math.max(left, right);
            }
        }
        
        // Step 3: If all characters in the current range meet the condition, return the length of the substring
        return end - start;
    }
}

Subscribe
Notify of

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Popular