424. Longest Repeating Character Replacement

51 阅读1分钟

image.png

方法:滑动窗口

  • 右边界先移动找到一个满足题意的可以替换 k 个字符以后,所有字符都变成一样的当前看来最长的子串,直到右边界纳入一个字符以后,不能满足的时候停下;

  • 然后考虑左边界向右移动,左边界只须要向右移动一格以后,右边界就又可以开始向右移动了,继续尝试找到更长的目标子串

  • 替换后的最长重复子串就产生在右边界、左边界交替向右移动的过程中

  • 为什么left边界要收缩?

    • 如果长度为 L 的子串不符合题目的要求,那么左边界固定,长度更长的子串也不符合题目的要求。
  • 内层循环里的 if 能不能改成 while?

    • 答:可以但没有必要。理由依然是:我们只关心最长替换 k 次以后重复子串的长度。正是因为多读了一个字符,使得 right - left + 1 - maxCount > k 成立;在 left++ 以后,由于可以不维护 maxCount 的定义,right - left + 1 - maxCount > k 不成立。因此 if 里面的代码块只会被执行一次。
class Solution {
    public int characterReplacement(String s, int k) {
        char[] arr = s.toCharArray();
        int left = 0, right = 0;

        int[] freq = new int[26]; // 记录字符出现的频率
        int maxCount = 0; // 出现最高频率的字符的次数
        int res = 0;
        while (right < arr.length) {
            // 因为每一次右边界读入一个字符,字符频数增加
            freq[arr[right] - 'A']++;
            maxCount = Math.max(maxCount, freq[arr[right] - 'A']);
            
            // 可以替换的字符数量不够了,收缩左边界
            if (right - left + 1 - maxCount > k) {
                freq[arr[left] - 'A']--;
                left++;
            }
            // 更新最大长度
            res = Math.max(res, right - left + 1);
            
            // 扩展右边界
            right++;
        }
        return res;
    }
}