424. Longest Repeating Character Replacement - Explanation

Problem Link

Description

You are given a string s consisting of only uppercase english characters and an integer k. You can choose up to k characters of the string and replace them with any other uppercase English character.

After performing at most k replacements, return the length of the longest substring which contains only one distinct character.

Example 1:

Input: s = "XYYX", k = 2

Output: 4

Explanation: Either replace the 'X's with 'Y's, or replace the 'Y's with 'X's.

Example 2:

Input: s = "AAABABB", k = 1

Output: 5

Constraints:

  • 1 <= s.length <= 1000
  • 0 <= k <= s.length


Topics

Recommended Time & Space Complexity

You should aim for a solution with O(n) time and O(m) space, where n is the length of the given string and m is the number of unique characters in the string.


Hint 1

Which characters would you replace in a string to make all its characters identical? Can you think with respect to the frequency of the characters?


Hint 2

It is always optimal to replace characters with the most frequent character in the string. Why? Because using the most frequent character minimizes the number of replacements required to make all characters in the string identical. How can you find the number of replacements now?


Hint 3

The number of replacements is equal to the difference between the length of the string and the frequency of the most frequent character in the string. A brute force solution would be to consider all substrings, use a hash map for frequency counting, and return the maximum length of the substring that has at most k replacements. This would be an O(n^2) solution. Can you think of a better way?


Hint 4

We can use the sliding window approach. The window size will be dynamic, and we will shrink the window when the number of replacements exceeds k. The result will be the maximum window size observed at each iteration.


Company Tags

Please upgrade to NeetCode Pro to view company tags.



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Sliding Window - The optimal solution uses a variable-size window that expands and contracts based on validity conditions
  • Hash Map / Frequency Counting - Tracking character frequencies within the current window to determine the most frequent character
  • Two Pointers - Managing left and right pointers to define and adjust the window boundaries

1. Brute Force

Intuition

The brute-force idea is to try every possible substring starting at every index.
For each start point, we expand the substring and keep track of how many times each character appears.
A substring is valid if we can make all its characters the same by replacing at most k of them.
To check this, we track the most frequent character inside the substring — everything else would need to be replaced.
If the number of replacements needed is within k, we update the answer.
This works but is slow because it checks many overlapping substrings.

Algorithm

  1. Initialize res = 0 to store the longest valid window.
  2. For each starting index i:
    • Create an empty frequency map and set maxf = 0.
    • Extend the substring by increasing j from i to the end:
      • Update the frequency of s[j].
      • Update maxf (most frequent character in the current window).
      • If the window size minus maxf is <= k, it is valid.
        • Update res with the window size.
  3. Return res after testing all starting positions.
class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        res = 0
        for i in range(len(s)):
            count, maxf = {}, 0
            for j in range(i, len(s)):
                count[s[j]] = 1 + count.get(s[j], 0)
                maxf = max(maxf, count[s[j]])
                if (j - i + 1) - maxf <= k:
                    res = max(res, j - i + 1)
        return res

Time & Space Complexity

  • Time complexity: O(n2)O(n ^ 2)
  • Space complexity: O(m)O(m)

Where nn is the length of the string and mm is the total number of unique characters in the string.


2. Sliding Window

Intuition

We try to make a valid window where all characters become the same, but instead of checking every substring, we fix a target character c and ask:

"How long can the window be if we want the entire window to become c using at most k replacements?"

We slide a window across the string and count how many characters inside it already match c.
If the number of characters that don't match c is more than k, the window is invalid, so we shrink it from the left.
By doing this for every possible character, we find the longest valid window.

This idea is simple and beginner-friendly because we only track:

  • how many characters match c
  • how many replacements are needed

Algorithm

  1. Put all unique characters of the string into a set charSet.
  2. For each character c in charSet:
    • Set l = 0 and count = 0 (count of c inside the window).
    • Slide the right pointer r across the string:
      • Increase count when s[r] == c.
      • If the window needs more than k replacements, move l forward and adjust count.
      • Update res with the current valid window size.
  3. Return the maximum window size found.
class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        res = 0
        charSet = set(s)

        for c in charSet:
            count = l = 0
            for r in range(len(s)):
                if s[r] == c:
                    count += 1

                while (r - l + 1) - count > k:
                    if s[l] == c:
                        count -= 1
                    l += 1

                res = max(res, r - l + 1)
        return res

Time & Space Complexity

  • Time complexity: O(mn)O(m * n)
  • Space complexity: O(m)O(m)

Where nn is the length of the string and mm is the total number of unique characters in the string.


3. Sliding Window (Optimal)

Intuition

We want the longest window where we can make all characters the same using at most k replacements.
The key insight is that the window is valid as long as:

window size – count of the most frequent character ≤ k

Why?
Because the characters that aren't the most frequent are the ones we would need to replace.

So while expanding the window, we track:

  • the frequency of each character,
  • the most frequent character inside the window (maxf).

If the window becomes invalid, we shrink it from the left.
This gives us one clean sliding window pass.

Algorithm

  1. Create a frequency map count and initialize l = 0, maxf = 0, and res = 0.
  2. Move the right pointer r across the string:
    • Update the frequency of s[r].
    • Update maxf with the highest frequency seen so far.
  3. If the window is invalid (window size - maxf > k):
    • Shrink the window from the left and adjust counts.
  4. Update the result with the valid window size.
  5. Return res at the end.
class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        count = {}
        res = 0

        l = 0
        maxf = 0
        for r in range(len(s)):
            count[s[r]] = 1 + count.get(s[r], 0)
            maxf = max(maxf, count[s[r]])

            while (r - l + 1) - maxf > k:
                count[s[l]] -= 1
                l += 1
            res = max(res, r - l + 1)

        return res

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(m)O(m)

Where nn is the length of the string and mm is the total number of unique characters in the string.


Common Pitfalls

Not Updating maxf Correctly

The variable maxf tracks the maximum frequency of any character in the current window. A common mistake is recalculating the maximum by iterating through all counts after shrinking the window. In the optimal solution, you do not need to decrease maxf when shrinking because keeping a stale (higher) maxf only makes the window condition stricter, which is still correct. However, misunderstanding this can lead to unnecessary complexity or bugs.

Shrinking the Window Too Aggressively

When the window becomes invalid (window size - maxf > k), you only need to shrink it enough to make it valid again. A common error is resetting the left pointer too far or not updating character counts properly when moving the left pointer. Make sure to decrement the count of s[l] before incrementing l.

Confusing Window Size Calculation

The window size is r - l + 1, not r - l. This off-by-one error is frequent and leads to incorrect validity checks. For example, if l = 0 and r = 2, the window contains 3 characters, not 2. Always double-check your window size formula in the condition (r - l + 1) - maxf <= k.