AlgoMaster Logo

Longest Repeating Character Replacement

Last Updated: March 21, 2026

medium
4 min read

Understanding the Problem

We need to find the longest substring where, after changing at most k characters, every character in the substring is the same. The key question is: for any given substring, what's the minimum number of changes needed to make all characters identical?

If a substring has length L and the most frequent character in it appears maxFreq times, then we need to change L - maxFreq characters to make the whole substring uniform. So the condition for a valid substring is: L - maxFreq <= k.

This reframing is the foundation for every approach. We're looking for the longest substring where the number of "non-majority" characters is at most k.

Key Constraints:

  • s.length up to 10^5 means O(n^2) is borderline. An O(n) or O(n log n) approach is preferred.
  • Only uppercase English letters (26 characters) means any per-character tracking is O(26) = O(1).
  • k can be as large as s.length, meaning we might be able to change every character. In that case, the answer is simply the entire string length.

Approach 1: Brute Force

Intuition

The most straightforward way: try every possible substring and check if it can be turned into a repeating character string with at most k replacements. For each starting index, expand the substring one character at a time, maintaining a frequency count. At each step, the number of replacements needed is windowLength - maxFrequency. Track the longest valid substring.

Algorithm

  1. For each starting index left from 0 to n - 1
  2. Initialize a frequency array of size 26 and a maxFreq variable
  3. Expand right from left to n - 1, updating the frequency of s[right]
  4. Update maxFreq to be the maximum value in the frequency array
  5. If (right - left + 1) - maxFreq <= k, update the answer with the current window length
  6. If (right - left + 1) - maxFreq > k, break (no point expanding further from this left)
  7. Return the maximum length found

Example Walkthrough

1left=0: window="A", maxFreq=1, changes=0 <= 1, len=1
0
right
A
left
1
A
2
B
3
A
4
B
5
B
6
A
1/10

Code

For each starting position, we're building the frequency count from scratch and expanding until the window becomes invalid. What if we could maintain the frequency count as we slide the window, instead of resetting it each time?

Approach 2: Sliding Window

Intuition

Instead of trying every starting point independently, we use two pointers to maintain a single window that we expand and shrink. The idea: expand right one step at a time. After each expansion, check if the window is still valid (windowSize - maxFreq <= k). If not, shrink from the left until it becomes valid again.

The frequency array updates incrementally. When right moves forward, we increment one count. When left moves forward, we decrement one count. No redundant work.

One subtlety: when we shrink the window by moving left forward, the maxFreq might decrease. We need to recompute it by scanning all 26 entries in the frequency array. Since 26 is a constant, this doesn't affect the overall O(n) time complexity.

Algorithm

  1. Initialize a frequency array, left = 0, maxLen = 0
  2. Iterate right from 0 to n - 1
  3. Increment freq[s[right]]
  4. Compute maxFreq as the maximum value in the frequency array
  5. While (right - left + 1) - maxFreq > k, decrement freq[s[left]], increment left, and recompute maxFreq
  6. Update maxLen = max(maxLen, right - left + 1)
  7. Return maxLen

Example Walkthrough

1right=0: window="A", maxFreq=1, changes=0 <= 1, maxLen=1
0
right
A
left
1
A
2
B
3
A
4
B
5
B
6
A
1/10

Code

Every time we shrink the window, we recompute maxFreq by scanning all 26 characters. But the answer can only improve when maxFreq increases. What if we just let maxFreq stay at its highest value and only update it upward?

Approach 3: Optimized Sliding Window

Intuition

This approach uses a clever observation: we never need to decrease maxFreq. Suppose the best valid window we've found so far has length bestLen. For the answer to improve, we need a window longer than bestLen. A longer valid window requires maxFreq to be higher (since windowSize - maxFreq <= k must hold, and we need a bigger windowSize). So any situation where maxFreq decreases is irrelevant to finding a better answer.

Instead of shrinking the window with a while loop until it's valid, we use an if statement. When the window is invalid, we move left forward by exactly one position (sliding the window) and move on. The window size either stays the same or grows. It never shrinks below the best valid size we've seen.

Algorithm

  1. Initialize a frequency array, left = 0, maxFreq = 0, maxLen = 0
  2. Iterate right from 0 to n - 1
  3. Increment freq[s[right]] and update maxFreq if this character's count is the new max
  4. If (right - left + 1) - maxFreq > k, decrement freq[s[left]] and increment left (slide window by 1)
  5. Update maxLen = max(maxLen, right - left + 1)
  6. Return maxLen

Example Walkthrough

1right=0: 'A', maxFreq=1, 1-1=0 <= 1, maxLen=1
0
right
A
left
1
A
2
B
3
A
4
B
5
B
6
A
1/8

Code