Longest Repeating Character Replacement
Longest substring replaceable into one character with ≤ k swaps — sliding window, max-frequency tracking, O(n).
- dsa
- sliding-window
- interview
- Meta
The problem
String s of uppercase letters, integer k. You may replace any character with another at most k times. Return the length of the longest substring containable of the same letter after those replacements.
s = "ABAB", k = 2 → 4 // replace both A's or both B's
s = "AABABBA", k = 1 → 4 // e.g. "AABA" → "AAAA"
Core inequality
In a window, let maxf = count of the most frequent character.
You need windowLen - maxf replacements to make the window uniform.
Valid iff windowLen - maxf ≤ k.
Brute
For every window, count freq, check inequality. O(n² · Σ).
Optimal sliding window
Expand right. Track counts and maxf. While invalid, advance left and decrement counts. Answer is max window length seen.
function characterReplacement(s: string, k: number): number {
const cnt = new Array<number>(26).fill(0);
let left = 0;
let maxf = 0;
let best = 0;
for (let right = 0; right < s.length; right++) {
const ri = s.charCodeAt(right) - 65;
cnt[ri]++;
maxf = Math.max(maxf, cnt[ri]);
// shrink until valid
while (right - left + 1 - maxf > k) {
cnt[s.charCodeAt(left) - 65]--;
left++;
// maxf may be stale — still correct for max length (see note)
}
best = Math.max(best, right - left + 1);
}
return best;
}
| Time | O(n) |
| Space | O(1) alphabet |
Stale maxf note
When shrinking, some solutions don’t recompute maxf. That’s OK for maximum window length: a stale (too large) maxf only makes the while condition stricter later; you never accept a longer invalid window, and any better answer still forces a larger true maxf when expanded. Recomputing maxf each shrink is clearer if you’re unsure:
// safer shrink
while (right - left + 1 - maxf > k) {
cnt[s.charCodeAt(left) - 65]--;
left++;
maxf = Math.max(...cnt); // O(26)
}
Walk "AABABBA", k=1
Windows grow; when need >1 replace, left moves. Best length 4.
Edge cases
- k = 0 → longest run of identical chars
- k ≥ n → n
- All unique letters
- Single character string
Common mistakes
- Using total unique count instead of max frequency
- Fixed window size only
- Lowercase char codes without offset care
Interview delivery
- Window valid iff len − maxf ≤ k.
- Sliding expand/shrink.
- Optional stale maxf discussion.
- O(n).
- Edge k=0.
Mental model
Sliding window of candidates for the final monochrome substring. The bottleneck is how many characters aren’t the mode of the window — those need replacements.
Why the answer is a length not a string
Problem only asks length. You don’t need to materialize replacements. If asked for any valid substring, store bestL/bestR when updating best.
Related windows
- Longest substring with ≤ k distinct characters
- Longest substring without repeating (k=0 special flavor)
- Min window covering a charset
Same expand/shrink skeleton, different validity predicate.
Out-loud answer
“Window valid if length − maxFrequency ≤ k. Expand right, shrink left while invalid, track max length. O(n) with fixed alphabet counts. k=0 reduces to longest run.”
Related
- Longest Substring Without Repeating
- Minimum Window Substring
- Longest Palindromic Substring
- Container With Most Water
- JavaScript Interview Guide