🧠
Sliding Window with Frequency Map and Max Count Tracking
💡 This approach uses a sliding window that expands and contracts to maintain the condition that the number of replacements needed is at most k. It’s more efficient and introduces the key insight of tracking the most frequent character in the current window.
Intuition
Keep expanding the window and track the count of the most frequent character. If the window size minus this count exceeds k, shrink the window from the left.
Algorithm
- Initialize two pointers (left and right) at the start of the string.
- Expand right pointer, update frequency of current character and track max frequency in window.
- If window size minus max frequency > k, move left pointer forward and update frequencies.
- Keep track of the maximum window size seen that satisfies the condition.
💡 The tricky part is maintaining max frequency efficiently and knowing when to shrink the window.
def characterReplacement(s: str, k: int) -> int:
freq = {}
left = 0
max_count = 0
max_len = 0
for right in range(len(s)):
freq[s[right]] = freq.get(s[right], 0) + 1
max_count = max(max_count, freq[s[right]])
while (right - left + 1) - max_count > k:
freq[s[left]] -= 1
left += 1
max_len = max(max_len, right - left + 1)
return max_len
# Driver code
if __name__ == '__main__':
print(characterReplacement("ABAB", 2)) # Expected output: 4
Line Notes
freq = {}Initialize frequency dictionary for current window
left = 0Left pointer starts at beginning
for right in range(len(s))Right pointer expands window
freq[s[right]] = freq.get(s[right], 0) + 1Update frequency of new character
max_count = max(max_count, freq[s[right]])Track max frequency in window
while (right - left + 1) - max_count > k:Shrink window if replacements exceed k
freq[s[left]] -= 1Decrease frequency of character leaving window
left += 1Move left pointer forward
max_len = max(max_len, right - left + 1)Update max length found
import java.util.*;
public class Solution {
public int characterReplacement(String s, int k) {
Map<Character, Integer> freq = new HashMap<>();
int left = 0, maxCount = 0, maxLen = 0;
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
freq.put(c, freq.getOrDefault(c, 0) + 1);
maxCount = Math.max(maxCount, freq.get(c));
while ((right - left + 1) - maxCount > k) {
char leftChar = s.charAt(left);
freq.put(leftChar, freq.get(leftChar) - 1);
left++;
}
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}
public static void main(String[] args) {
Solution sol = new Solution();
System.out.println(sol.characterReplacement("ABAB", 2)); // Expected output: 4
}
}
Line Notes
Map<Character, Integer> freq = new HashMap<>();Frequency map for current window
int left = 0, maxCount = 0, maxLen = 0;Initialize pointers and trackers
for (int right = 0; right < s.length(); right++) {Expand window from right
freq.put(c, freq.getOrDefault(c, 0) + 1);Update frequency of new character
maxCount = Math.max(maxCount, freq.get(c));Track max frequency in window
while ((right - left + 1) - maxCount > k) {Shrink window if replacements exceed k
freq.put(leftChar, freq.get(leftChar) - 1);Decrease frequency of character leaving window
left++;Move left pointer forward
maxLen = Math.max(maxLen, right - left + 1);Update max length found
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;
int characterReplacement(string s, int k) {
unordered_map<char, int> freq;
int left = 0, maxCount = 0, maxLen = 0;
for (int right = 0; right < (int)s.size(); right++) {
freq[s[right]]++;
maxCount = max(maxCount, freq[s[right]]);
while ((right - left + 1) - maxCount > k) {
freq[s[left]]--;
left++;
}
maxLen = max(maxLen, right - left + 1);
}
return maxLen;
}
int main() {
cout << characterReplacement("ABAB", 2) << endl; // Expected output: 4
return 0;
}
Line Notes
unordered_map<char, int> freq;Frequency map for current window
int left = 0, maxCount = 0, maxLen = 0;Initialize pointers and trackers
for (int right = 0; right < (int)s.size(); right++) {Expand window from right
freq[s[right]]++;Update frequency of new character
maxCount = max(maxCount, freq[s[right]]);Track max frequency in window
while ((right - left + 1) - maxCount > k) {Shrink window if replacements exceed k
freq[s[left]]--;Decrease frequency of character leaving window
left++;Move left pointer forward
maxLen = max(maxLen, right - left + 1);Update max length found
function characterReplacement(s, k) {
const freq = {};
let left = 0, maxCount = 0, maxLen = 0;
for (let right = 0; right < s.length; right++) {
freq[s[right]] = (freq[s[right]] || 0) + 1;
maxCount = Math.max(maxCount, freq[s[right]]);
while ((right - left + 1) - maxCount > k) {
freq[s[left]]--;
left++;
}
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}
// Driver code
console.log(characterReplacement("ABAB", 2)); // Expected output: 4
Line Notes
const freq = {};Frequency map for current window
let left = 0, maxCount = 0, maxLen = 0;Initialize pointers and trackers
for (let right = 0; right < s.length; right++) {Expand window from right
freq[s[right]] = (freq[s[right]] || 0) + 1;Update frequency of new character
maxCount = Math.max(maxCount, freq[s[right]]);Track max frequency in window
while ((right - left + 1) - maxCount > k) {Shrink window if replacements exceed k
freq[s[left]]--;Decrease frequency of character leaving window
left++;Move left pointer forward
maxLen = Math.max(maxLen, right - left + 1);Update max length found
Each character is visited at most twice by left and right pointers. Frequency map size is constant (26 uppercase letters).
💡 For n=10^5, this means roughly 200,000 operations, which is efficient and suitable for interviews.
Interview Verdict: Accepted
This is the standard optimal approach for this problem and is expected in interviews.