You are given a string s and an integer k. You can choose any character of the string and change
it to any other uppercase English character. You can perform this operation at most k times.
Return the length of the longest substring containing the same letter you can get after performing the above operations.
Example 1:
Input: s = "ABAB", k = 2
Output: 4
Explanation: Replace the two 'A's with two 'B's or vice versa.
Example 2:
Input: s = "AABABBA", k = 1
Output: 4
Explanation: Replace the one 'A' in the middle with 'B' and form "AABBBBA".
The substring "BBBB" has the longest repeating letters, which is 4.
There may exists other ways to achieve this answer too.
Playground: Leetcode 424
Key Observations
A few key questions that need to be addressed are:
Q1. What is the minimum number of replacements required to make all characters in a substring the same?
The minimum number of replacements required to make all characters in a substring the same
is (length of substring - frequency of the most frequent character).
For example: If we want to convert the entire string "AABBAC" into a substring
containing the same letter, the minimum number of replacements required is 3, achieved by
keeping A, i.e., the most frequent character.
| Target character | Characters to replace | Replacements |
|---|---|---|
A | B B C | 3 |
B | A A A C | 4 |
C | A A B B A | 5 |
Q2. What makes a substring eligible for conversion?
A substring is eligible to be converted into a substring containing the same letter if the minimum number of replacements required is <= k.
For example:

Naive Approach - Nested Loops
Iterate over every substring in s, check if it is eligible to be converted into a substring
containing the same letter, and keep track of the longest eligible substring observed.
Algorithm
1. Iterate over each character in "s", treating it as the starting position of a substring.
2. For each starting position, initialize a frequency map to track the character in the current
substring.
3. Expand the substring one character at a time towards the right. Update the frequency of each
newly added character.
4. For the current substring, check if the number of replacements required is <= k.
5. Update the longest eligible substring if necessary.
6. Return the length of the longest eligible substring.
Implementation
Time Complexity
The outer loop runs n times, where n = s.length(). For the ith iteration of the outer
loop, the inner loop runs (n - i) iterations.
Since each operation performed inside the inner loop takes constant time, i.e., O(1). Therefore, the total number
of operations performed is proportional to:
(n - 0) + (n - 1) + (n - 2) + ... + (n - (n - 1)) = n + (n - 1) + (n - 2) + ... + 1
= n(n + 1) / 2
Since the total number of operations is of the order of n², the overall time complexity is O(n²).
Space Complexity
We use a HashMap to store the frequency of each character in current substring.
In the worst case, when all characters in s are unique, the HashMap can contain upto n distinct
characters simnultaneously, where n = s.length().
Therefore, the overall time complexity is O(n).
Key Optimizations
For any starting character ch, we expand the substring towards the right. If, at some point, the current
substring becomes ineligible, adding more characters to the right cannot make it eligible again.
For the next starting character, we also don't need to restart the exploration from the beginning. All smaller substrings contained between the new starting position and the previous stopping position cannot give us a longer answer. We can continue expanding from the position where the previous exploration ended.

Suitable Approach - Sliding Window Technique
Maintain a single window using two pointers: left (marks the start of the current window)
and right (marks the end of the current window).
Instead of restarting the inner loop for every starting position, expand right and move
left forward whenever the current window becomes ineligible.
Algorithm
1. Initialize:
a. A variable "longestSubstringLength" to track the length of the longest eligible substring
found so far.
b. A variable "mostFrequentCharacterFrequency" to track the frequency of the most frequent
character in the current window.
c. Two pointers "left" and "right" to represent the boundaries of the current window.
d. A frequency map "frequencyMap" to track the frequency of each characters present in the
current window.
2. Start expanding "right" one character at a time:
a. Update the frequency of the newly added character in "frequencyMap".
b. Update "mostFrequentCharacterFrequency" if necessary.
c. While the current substring is ineligible:
i. Increment "left" to shrink the window.
ii. Update the frequency of the character removed from the window.
d. Once the window is eligible, update "longestSubstringLength" if necessary.
3. Return "longestSubstringLength".
Implementation
Time complexity
The checks and updates performed at each step take contant time. Hence, the
time complexity is dependent on the number of times the left and right
pointers move.
Both left and right pointers only move forward. The right pointer
increments exactly n times. The left pointer moves at most n times
over the entire life of the algorithm.
Because each pointer traverses the string at most once, the total index
movements are bounded by 2n. Hence, the overall time complexity is
O(2n) ~ O(n).
Space Complexity
In the worst case, when all characters in s are distinct, the frequencyMap can
store the frequency of all n characters simnultaneously.
Since the space required by the frequencyMap is bounded by n, the overall
space complexity is O(n).