Loading problems...
TL;DR: Use a sliding window to expand a substring while maintaining a count of the most frequent character; shrink the window from the left only when the number of characters needed to be replaced exceeds k.
The Longest Repeating Character Replacement problem asks us to find the length of the longest substring containing only one distinct letter after performing at most k replacement operations. Given a string s, we can choose any character in a substring and change it to any other uppercase English character. Our goal is to maximize the length of a substring consisting of repeating characters.
This is a popular interview question, often appearing in rounds for Google and Amazon, as it tests the ability to manage state within a linear scan—a hallmark of the "LeetCode 424 solution."
The naive approach involves checking every possible substring to see if it can be converted into a valid repeating string using at most k replacements.
For every substring s[i...j]:
max_freq).replacements = substring_length - max_freq.replacements <= k, the substring is valid. We record its length.plaintextmax_length = 0 for i from 0 to length(s): for j from i to length(s): substring = s[i...j] freq_map = count_chars(substring) max_f = max_value(freq_map) if (length(substring) - max_f) <= k: max_length = max(max_length, length(substring))
Complexity Analysis:
Why it fails:
With constraints allowing s.length up to , an or even solution will immediately trigger a Time Limit Exceeded (TLE). We need a linear or near-linear approach.
The key to optimizing the brute force approach lies in how we validate the substring. A substring is valid if the number of characters that are not the dominant character is less than or equal to k.
Mathematically, the condition is:
Instead of recalculating frequencies for every new substring, we can maintain a running frequency count as we slide a window across the string.
max_freq and the window length.k replacements), we shrink the window from the left. This reduces the window length and updates the frequency map, restoring validity.Visual Description:
Imagine the window as an elastic band stretching over the string. The right end pulls forward to capture more characters. As it stretches, we track the count of the "dominant" character inside. If the number of "non-dominant" characters (the holes in our pattern) exceeds k, the left end of the elastic band snaps forward, shrinking the window until the number of holes is again.

Consider s = "AABABBA", k = 1.
left=0, right=0, max_freq=0.max_freq (A) = 1. Valid (). Length 1.max_freq (A) = 2. Valid (). Length 2.max_freq (A) = 2. Valid (). Length 3.max_freq (A) = 3. Valid (). Length 4.max_freq (A) = 3.
s[0] ('A'). left becomes 1. Window is "ABAB".max_freq (B) = 3.
s[1] ('A'). left becomes 2. Window is "BABB".max_freq (B) = 3.
s[2] ('B'). left becomes 3. Window is "ABBA".Max length recorded was 4.
The algorithm is correct because the sliding window invariant is maintained at every step.
right, the left pointer is positioned at the smallest index such that the window s[left...right] is valid (or, in the optimized version, left moves just enough to maintain the maximum window size seen so far).right pointer traverses every possible end position of a substring.k constraint, we ensure that if a valid window of length L exists, the algorithm will reach a state where right - left + 1 == L.cpp#include <string> #include <vector> #include <algorithm> using namespace std; class Solution { public: int characterReplacement(string s, int k) { vector<int> count(26, 0); int left = 0; int maxCount = 0; int maxLength = 0; for (int right = 0; right < s.length(); ++right) { // Add current character to window count[s[right] - 'A']++; // Update the count of the most frequent character in the current window maxCount = max(maxCount, count[s[right] - 'A']); // Current window length is (right - left + 1) // Replacements needed = Window Length - maxCount // If replacements needed > k, shrink window if ((right - left + 1) - maxCount > k) { count[s[left] - 'A']--; left++; } // Update global maximum length maxLength = max(maxLength, right - left + 1); } return maxLength; } };
javaclass Solution { public int characterReplacement(String s, int k) { int[] count = new int[26]; int left = 0; int maxCount = 0; int maxLength = 0; for (int right = 0; right < s.length(); right++) { // Add current character to window char currentChar = s.charAt(right); count[currentChar - 'A']++; // Track the most frequent character count in the current window history maxCount = Math.max(maxCount, count[currentChar - 'A']); // If the window is invalid (replacements needed > k), slide left pointer // Note: We use 'if' instead of 'while' here because we only need to // shift the window, not strictly shrink it to minimum valid size, // to find the maximum length. if ((right - left + 1) - maxCount > k) { count[s.charAt(left) - 'A']--; left++; } maxLength = Math.max(maxLength, right - left + 1); } return maxLength; } }
pythonclass Solution: def characterReplacement(self, s: str, k: int) -> int: count = {} left = 0 max_freq = 0 max_length = 0 for right in range(len(s)): # Add current char to frequency map char = s[right] count[char] = count.get(char, 0) + 1 # Update max frequency seen in the current window max_freq = max(max_freq, count[char]) # Check validity: length - max_freq <= k # If invalid, shrink from the left if (right - left + 1) - max_freq > k: count[s[left]] -= 1 left += 1 # Update result max_length = max(max_length, right - left + 1) return max_length
Time Complexity:
The right pointer iterates through the string once ( steps). The left pointer can move at most times in total. Operations inside the loop (map updates) are . Thus, the total time is linear.
Space Complexity: We store frequencies for uppercase English letters. The size of the frequency array is fixed at 26, which is constant space regardless of input size .
The Sliding Window - Variable Size pattern is versatile. Understanding the logic for "LeetCode 424 Solution" helps with:
t)In all these cases, the core strategy remains: Expand right to satisfy a condition (or find a candidate), and increment left to optimize or restore validity.
Why does the naive solution get TLE?
Why do we check (right - left + 1) - maxCount > k?
k.Do we need to decrement maxCount when shrinking?
maxCount after decrementing left.maxCount. If the window shrinks, keeping the old maxCount simply means the condition is tighter, but we won't miss a new global maximum because a new max would require a higher frequency anyway.