AlgoMaster Logo

Longest Substring with At Least K Repeating Characters

mediumFrequencyUpdated September 21, 2026

Understanding the Problem

We need to find the longest substring where every character that appears in it appears at least k times. This is not about finding a single character that repeats k times. Every character in the substring must meet the threshold. If even one character falls short, the entire substring is invalid.

The "at least k" constraint applies per-character within the substring, not globally. A character that appears 100 times in the full string might appear only once in a particular substring, disqualifying it. And unlike sliding window problems where the constraint can be checked incrementally as the window grows, here the validity of a window depends on all characters at once, so adding one character can invalidate a window that was previously valid.

One property drives most of the solutions: any character that appears fewer than k times in the entire string can never belong to any valid substring. Such characters act as splitting points that divide the string into segments. The answer must lie entirely within one of those segments. This property leads directly to a divide and conquer approach, and to a sliding window variant that fixes the number of distinct characters.

Key Constraints:

  • 1 <= s.length <= 10^4 → With n up to 10,000, even O(n^2) approaches should work within time limits. But O(n) or O(n log n) is ideal.
  • s consists of only lowercase English letters → At most 26 distinct characters. This bound lets us enumerate over the number of distinct characters allowed in a window (1 to 26), which is what makes the sliding window approach work.
  • 1 <= k <= 10^5 → k can be larger than the string length, in which case the answer is always 0.

Approach 1: Brute Force

Intuition

Check every possible substring and test whether it satisfies the constraint. For each substring, count the frequency of every character and verify that all characters appear at least k times. Pick every starting index, extend to every ending index, count frequencies as you extend, and track the longest substring that passes.

Algorithm

  1. Iterate over all possible starting indices i from 0 to n-1.
  2. For each starting index, iterate over all ending indices j from i to n-1.
  3. Count the frequency of each character in the substring s[i..j].
  4. Check if every character in the substring has a frequency of at least k.
  5. If valid, update the maximum length.
  6. Return the maximum length found.

Visualization and Code

Loading animation...

This checks every substring independently and ignores the structure of the problem. The next approach uses the low-frequency characters to split the string into smaller independent subproblems.

Approach 2: Divide and Conquer

Intuition

If a character appears in s fewer than k times total, it can never be part of any valid substring, so every valid substring must avoid it entirely. That character splits the string into segments, and the answer lies entirely within one of those segments.

This gives a recursive strategy. Count character frequencies for the current string. Find a character that appears fewer than k times. Split the string at every occurrence of that character, then recursively solve each segment. The answer is the maximum across all segments.

If every character in the current string already meets the threshold, the entire string is valid and we return its length. That is the base case.

Algorithm

  1. Count the frequency of each character in the current string.
  2. If every character has frequency >= k, return the length of the string (the whole string is valid).
  3. Otherwise, find a character with frequency < k.
  4. Split the string at every occurrence of that character.
  5. Recursively solve each segment.
  6. Return the maximum result across all segments.

Visualization and Code

Loading animation...

The divide and conquer approach is efficient but recursive. The next approach solves the problem iteratively with a sliding window. The obstacle is the shrink condition, which the approach removes by fixing the number of distinct characters allowed in the window.

Approach 3: Sliding Window with Unique Character Count

Intuition

A standard sliding window fails here because there is no monotonic shrink condition. When the window expands and a new character enters with frequency below k, shrinking from the left could remove a character that was already valid, so the window length is not a function we can grow and shrink greedily.

Adding one constraint fixes this. Instead of asking for the longest valid substring directly, ask for the longest valid substring that contains exactly t distinct characters. Fixing t gives a clean shrink condition: whenever the window holds more than t distinct characters, shrink from the left until it holds exactly t again. When the window holds exactly t distinct characters and all t of them have frequency at least k, the window is valid.

A valid answer has some number of distinct characters between 1 and 26, so running this windowed scan once for each t from 1 to 26 covers every case. Each scan is O(n), so the total is O(26n) = O(n).

Algorithm

  1. For each target number of unique characters t from 1 to 26:
    1. Initialize a sliding window with left = 0, right = 0.
    2. Track the frequency of each character in the window, the count of unique characters, and the count of characters that meet the k threshold.
    3. Expand right: add the character, update counts.
    4. If unique characters exceed t, shrink from left until unique characters equal t.
    5. If unique characters equal t and all t characters have frequency >= k, update the maximum length.
  2. Return the overall maximum.

Visualization and Code

Loading animation...