Longest Repeating Character Replacement

This problem looks scary at first. You are allowed to change some letters. So where do you even start? The interviewer wants to see if you can spot the hidden rule. The rule is simple once you find it. A window is valid when only a few letters need changing. That tiny idea turns a messy problem into a clean sliding window.

🎯 The Problem

You get a string of capital letters and a number k. Here are the rules.

  • You can change up to k letters to any other letter.
  • Your goal is the longest run where all letters become the same.
  • A run that sits next to itself is a substring. A substring is a stretch of characters with nothing skipped.
  • Return the length of that longest run.

Take the string "AABABBA" and k as 1. The window "AABA" has three A and one B. Change that one B to A and you get four A in a row. That uses only one change. So the answer is 4.

Input: s = "AABABBA", k = 1
Output: 4
Explanation: Change one B to A to make "AAAA", a run of length 4.

Here is the idea drawn out. Inside any window, you keep the most common letter and change the rest.

A

A

B

A

window AABA, three A and one B

change one B, get AAAA, length 4

🐢 Approach 1: Check Every Window (Brute Force)

The idea in one line: try every possible window and count its changes from scratch.

The idea:

  • Look at every start and every end.
  • Count the letters inside each window.
  • The most common letter stays. The rest are changes.

How it works:

  • For each window, find the most common letter.
  • The changes needed is window size minus that count.
  • If the changes are k or less, the window is allowed.
  • Keep the longest allowed window.

Why it is weak:

  • You build and count every window from scratch.
  • That repeats a huge amount of work.
  • The nested passes make it O(n²).

Here is the brute-force code for that idea:

character_replacement_brute_force.py
from collections import Counter
def character_replacement(s, k):
best = 0
for left in range(len(s)):
counts = Counter()
for right in range(left, len(s)):
counts[s[right]] += 1
window = right - left + 1
if window - max(counts.values()) <= k:
best = max(best, window)
return best

⚡ Approach 2: Sliding Window With Counts (Best)

The idea in one line: a window is valid when its size minus the most common letter count is at most k, so slide and reuse the counts.

The idea:

  • The changes for a window is window size minus the count of the most common letter.
  • You keep the most common letter and change everyone else.
  • So a window is valid when window size minus the max count is at most k.

How it works:

  • Move the right edge forward and add the new letter to a count table.
  • A count table remembers how many times each letter showed up.
  • If window size minus max count is greater than k, the window needs too many changes.
  • Then move the left edge forward and lower that letter’s count.
  • That shrinks the window back to a valid size.

Why it is fast:

  • The counts are reused, not rebuilt.
  • Each letter enters once and leaves once.
  • One clean pass, so O(n).

Here is the window growing, then shrinking once it needs too many changes, then growing again.

right=0 window=A maxcount=1 changes=0

window=AA maxcount=2 changes=0

window=AAB maxcount=2 changes=1 valid

window=AABA maxcount=3 changes=1 valid size=4

window=AABAB maxcount=3 changes=2 too many

move left, shrink window back to valid

Steps to Solve

  1. Set the left edge at the start. Keep a count table for the letters and a running max count.
  2. Move the right edge across the string and add each letter to the count table.
  3. Update the max count with the new letter’s count.
  4. If window size minus max count is greater than k, move the left edge forward and lower that letter’s count.
  5. After each step, record the window size as a possible answer.
  6. When the right edge reaches the end, return the largest size you saw.

This Python version uses a dictionary of letter counts and slides the left edge when the window needs too many changes.

char_replacement.py
def character_replacement(s, k):
count = {} # how many times each letter is in the window
left = 0 # left edge of the window
best = 0 # longest valid window seen
max_count = 0 # count of the most common letter in the window
for right in range(len(s)):
count[s[right]] = count.get(s[right], 0) + 1 # add new letter
max_count = max(max_count, count[s[right]]) # track most common
while (right - left + 1) - max_count > k: # too many changes
count[s[left]] -= 1 # drop leftmost
left += 1 # shrink window
best = max(best, right - left + 1) # update best size
return best
s = "AABABBA"
print(character_replacement(s, 1))

The output of the above code will be:

4

Let us walk through the Python version line by line and see why each line is there.

count = {} is an empty dictionary. It remembers how many times each letter sits inside the window right now. We need these counts to find the most common letter.

left = 0 is the left edge of the window. best = 0 keeps the longest valid window we have found. max_count = 0 is the count of the most common letter inside the window.

for right in range(len(s)): moves the right edge across the string. Each loop pulls in one new letter.

count[s[right]] = count.get(s[right], 0) + 1 adds the new letter to the count table. get returns the old count or zero if the letter is new. Then we add one.

max_count = max(max_count, count[s[right]]) updates the most common count. The new letter might now be the most common one.

while (right - left + 1) - max_count > k: checks the rule. right - left + 1 is the window size. Subtract the most common count and you get the letters you would have to change. If that is more than k, the window is not allowed.

count[s[left]] -= 1 and left += 1 shrink the window from the left. We lower the leftmost letter’s count and move the left edge forward. The while keeps shrinking until the window is allowed again.

best = max(best, right - left + 1) records the window size if it is the biggest so far.

return best gives back the length of the longest valid window.

Note

Notice we never lower max_count when we shrink. That is fine. The window only grows when a higher max count is found, so the answer stays correct and the code stays fast.

⏱️ Time and Space Complexity

The brute force counts every window from scratch, so it is slow at O(n²). The sliding window reuses the counts and touches each letter at most twice. So it runs in O(n) time. The memory holds counts for the 26 capital letters, which is a fixed small amount.

Approach Time Complexity Space Complexity
Brute force (check every window) O(n²) O(1)
Sliding window with counts O(n) O(1)

🧩 Key Takeaways

  • ✅ A window is valid when window size minus the most common letter count is at most k.
  • ✅ Keep the most common letter and change the rest. That is the smallest number of changes.
  • ✅ Slide the right edge to grow and the left edge to shrink when the window needs too many changes.
  • ✅ Reusing the counts instead of recounting takes the time from O(n²) down to O(n).
  • ✅ Talk through the brute force first, then explain the valid-window rule. That shows your thinking.

Check Your Knowledge

4 questions Show quiz Hide quiz

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    When is a window valid in this problem?

    Why: You change every letter except the most common one, so the changes needed is window size minus the max count, which must be at most k.

  2. 2

    Why do we keep the most common letter in the window?

    Why: Keeping the most common letter and changing the others gives the smallest number of changes for that window.

  3. 3

    What do we do when a window needs more than k changes?

    Why: We shrink the window from the left until it becomes valid again, lowering the leftmost letter's count.

  4. 4

    What is the time complexity of the sliding window solution?

    Why: Each letter enters and leaves the window at most once and the counts are reused, so the work is linear, O(n).

🚀 What’s Next?