Longest Repeating Character Replacement

Updated on 09 June, 2025
Longest Repeating Character Replacement header image

Problem Statement

The task here is to determine the maximum possible length of a substring that can have identical characters after certain permitted modifications. Specifically, you are supplied with a string s containing only uppercase English letters and a number k. You can replace any of the characters in s with another uppercase letter, but you can only do this up to k times. Your goal is to ascertain the length of the longest possible substring where all letters are the same, after performing a maximum of k such modifications.

Examples

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.

Constraints

  • 1 <= s.length <= 105
  • s consists of only uppercase English letters.
  • 0 <= k <= s.length

Approach and Intuition

To solve this problem, we can use a sliding window approach coupled with frequency tracking. The idea is based on maintaining a window of characters (substring) where we aim to replace the least frequent characters in that window to match the most frequent character, such that the total number of modifications does not exceed k. Here’s a step-by-step guide:

  1. Initialize max_len to track the maximum length of the desired substring and max_count to track the count of the most frequent character within the window.
  2. Use two pointers, start and end, to denote the window's boundaries.
  3. As you expand the window by moving end to the right:
    • Update the frequency count of the character at index end.
    • Update max_count if the current character's frequency in the window exceeds previous max_count.
  4. Check if the window size minus the max_count (which represents the number of replacements needed to make all chars in the current window the same as the most common char) is greater than k:
    • If true, this means more replacements are needed than are allowed. Therefore, reduce the size from the left by advancing the start pointer to the right, and adjust the frequency table accordingly.
    • If false, calculate the potential new maximum length and update max_len if it's greater than the previous max_len.
  5. Repeat steps 3-4 until end has scanned all characters in the string s.

This approach ensures that at each step, the window size represents the length of the longest possible substring that can be transformed using a maximum of k modifications to have all identical characters. The sliding window technique efficiently narrows down the possibilities by dynamically adjusting its size based on the feasibility of transformation under the given constraints.

Solutions

  • Java
  • JavaScript
  • Python
java
class Solution {
    public int maxRepeatingCharacterChange(String inputStr, int allowableChanges) {
        int leftIndex = 0;
        int[] charCounts = new int[26];
        int maxCharCount = 0;
        int maxLength = 0;

        for (int rightIndex = 0; rightIndex < inputStr.length(); rightIndex++) {
            int currentCharIndex = inputStr.charAt(rightIndex) - 'A';
            charCounts[currentCharIndex]++;
            
            maxCharCount = Math.max(maxCharCount, charCounts[currentCharIndex]);

            if (rightIndex + 1 - leftIndex - maxCharCount > allowableChanges) {
                int leftCharIndex = inputStr.charAt(leftIndex) - 'A';
                charCounts[leftCharIndex]--;
                leftIndex++;
            }

            maxLength = Math.max(maxLength, rightIndex + 1 - leftIndex);
        }

        return maxLength;
    }
}

The Java solution provided tackles the problem of finding the maximum length of a substring that can be obtained by replacing at most a given number of characters to make the substring consist of the same character. Follow these detailed steps to understand the implemented algorithm:

  1. Initialize leftIndex to track the start of the sliding window, an integer array charCounts to record the frequency of each character within the window, maxCharCount to keep track of the count of the most frequent character in the window, and maxLength to store the length of the longest valid substring found.

  2. Iterate through the string using rightIndex to represent the end of the sliding window. For each character at rightIndex:

    • Convert the character to its corresponding index in charCounts and increment its count.
    • Update maxCharCount to be the maximum of its current value and the count of the newly added character.
  3. After updating maxCharCount, check if the window size minus maxCharCount is greater than the allowable number of changes (allowableChanges). If true, it means the window is not valid and needs adjustment:

    • Decrease the count of the character at leftIndex in charCounts.
    • Increment leftIndex to reduce the window size from the left.
  4. Update maxLength to be the maximum of its current value and the current window size.

  5. After traversing the entire string, return maxLength, which now contains the length of the longest valid substring achievable under the given constraints.

This solution effectively utilizes a sliding window technique combined with the frequency array to efficiently solve the problem by maintaining a balance between expanding the window and contracting it when the limit of allowable replacements is exceeded.

js
function longestValidSubstring(inpStr, maxChanges) {
    let initial = 0;
    let freqCounter = {};
    let maxFreq = 0;
    let maxLength = 0;
    for (let terminal = 0; terminal < inpStr.length; terminal += 1) {
        freqCounter[inpStr[terminal]] = (freqCounter[inpStr[terminal]] || 0) + 1;
        maxFreq = Math.max(maxFreq, freqCounter[inpStr[terminal]]);

        while (terminal + 1 - initial - maxFreq > maxChanges) {
            freqCounter[inpStr[initial]] -= 1;
            initial += 1;
        }

        maxLength = Math.max(maxLength, terminal + 1 - initial);
    }
    return maxLength;
}

The problem at hand involves finding the length of the longest substring in a given string where the number of maximum character changes is constrained by maxChanges. The solution employs a sliding window approach by utilizing two pointers, initial and terminal, to dynamically adjust the window's size and calculate the longest valid substring. Here’s a summary of how the solution works:

  • Initialize initial to 0, which denotes the starting index of the sliding window.
  • Use an object freqCounter to keep track of the frequency count of each character within the current window.
  • Keep record of the maximum frequency of any character in the current window using maxFreq.
  • Use maxLength to store the length of the longest valid substring found so far.

Each time a new character is considered at the terminal pointer:

  • Update the frequency of that character in freqCounter.
  • Update maxFreq to reflect the highest occurrence of any single character within the current window.
  • If the needed replacements exceed maxChanges, shrink the window from the left by incrementing initial and adjusting the count in freqCounter for the character getting removed.
  • Update maxLength to the maximum length between maxLength and the current window size.

Finally, after iterating through the string, the function returns maxLength. This value represents the length of the longest substring that can be obtained by making at most maxChanges character replacements.

This JavaScript implementation efficiently handles varying input sizes and constraints by modulating the window size based on the allowability of replacements, providing an optimal solution with a complexity that balances between window adjustments and character frequency maintenance.

python
class Solution:
    def maxReplacement(self, string: str, max_changes: int) -> int:
        left = 0
        char_count = {}
        highest_count = 0
        max_len = 0
        
        for right in range(len(string)):
            char_count[string[right]] = char_count.get(string[right], 0) + 1
            highest_count = max(highest_count, char_count[string[right]])
            
            while (right - left + 1) - highest_count > max_changes:
                char_count[string[left]] -= 1
                left += 1
            
            max_len = max(max_len, right - left + 1)
        
        return max_len

The Python solution provided tackles the problem of finding the length of the longest substring that can be obtained by replacing at most 'max_changes' characters in the input string with any other character. Let's break down the approach and how the function works:

  • Initialize two pointers, 'left' and 'right', to track the substring's boundaries. Use a dictionary 'char_count' to store the frequency of each character in the current window (substring between 'left' and 'right').

  • Iterate over the string with the 'right' pointer, expanding the window to the right each time.

  • Increase the count of the current character in the 'char_count' dictionary and update 'highest_count', which keeps the count of the most frequent character in the current window.

  • Check if the current window size minus 'highest_count' is greater than 'max_changes'. If so, this window is invalid, and the 'left' pointer should be moved to the right until the window becomes valid again, decrementing the count of the character that 'left' pointed to.

  • Continuously update 'max_len', which holds the maximum length of all valid windows found so far.

  • Finally, return 'max_len', which is the length of the longest valid window you have identified.

This approach utilizes the sliding window technique combined with a dynamic tracking of character counts to ensure that at most 'max_changes' operations are needed to make all characters in the window the same. The O(n) time complexity (where n is the length of the string) makes this solution efficient for larger input sizes.

Comments

No comments yet.