LeetCode 424. Longest Repeating Character Replacement

59 阅读2分钟

这道滑动窗口的题理解了很久,与一般的滑动窗口题不同,在这里记录下 424.Longest Repeating Character Replacement

题意:
给你一个字符串 s 和一个整数 k 。你可以选择字符串中的任一字符,并将其更改为任何其他大写英文字符。该操作最多可执行 k 次。

在执行上述操作后,返回包含相同字母的最长子字符串的长度。

解题
一般的滑动窗口题的解法是定义左右两个指针,都从下标零开始,然后右指针不断向右移动扩大窗口,当满足某个条件时,比如窗口内各个数之和大于某个值,右指针停止移动,左指针开始向右移动;这个移动一般是个循环操作,因为左指针需要不断移动才能使得条件不满足,而不是只移动一次就能做到不满足条件。模板如下:

public int sildeWindows(int target, int[] nums) {
        int left = 0, right = 0, min = Integer.MAX_VALUE, sum = 0;
        while (right < nums.length) {
            ...
            while (Conditions) {
                ...
                left++;
            }
            right++
        }
        return ;
    }

可以从代码模板看出一共有两个循环。 再看看LeetCode424 替换后的最长重复字符这道题: 这道题因为有K个与出现次数最多的字母不相同的字符可以被替换,意思即是有K个容错机会。最后结果肯定是滑动窗口内出现次数最多的字母的出现次数+K(如果K个容错机会都能用掉的话)

  • 如果想要知道窗口里哪个字母的出现次数最多,则我们需要记录每个纳入窗口的字母的出现次数,然后进行比较得出最多的,而我们只需要知道出现次数最多的,其他不需要知道,不管是有多少个。
  • 当右指针移动遇到什么条件会停止呢?答:当窗口内K个的容错机会被用光时。
    窗口的长度为right-left+1,窗口内出现次数最多的字母从上一点的比较中我们也已经得到,记为max,所 以当max+K > right-left+1时,说明有K个以上与max不相同的字母。
  • 当右指针满足条件停止移动时,左指针应该怎样移动呢?一般的题目需要定义循环操作不断移动左指针,正如上面模板里的一样。
    但在这里,我们只需要将左指针一起向右平移一位就可以了,为什么? 以BBBACD,K=2为例,此时假设在移动过程中,左指针只在第一个B上,右指针指向D,此时已经不满足条件,而当右指针还指在C时,整个滑动窗口已经是此时最大的了。所以保持此时最大窗口不动直到遇到更大的,所以左指针只需要移动一位就可以。
  • 就算某一刻你发现框里元素都不一样,但不要怀疑,因为它曾经辉煌过,它会一直呈现它窗口最大时候的状态。现在我是这样:aaab【cdef】,是因为曾经我:【aaab】cdef (容错次数K=1)
  • 最后最大窗口长度已经被固定住了,所以当滑动到最后时,字符串长度-left就是最大窗口长度。 代码如下:
public int characterReplacement(String s, int k) {
    int left = 0, right = 0, max = Integer.MIN_VALUE;
    int[] arr = new int[26];
    while (right < s.length()) {
        char c = s.charAt(right);
        arr[c - 'A'] += 1;
        max = Math.max(max, arr[c-'A']);
        if (k + max < right -left +1) {
            arr[s.charAt(left) - 'A'] --;
            left++;
        }
        right ++;
    }
    //Maximum sliding window is fixed
    return s.length() - left;
}

定义了26位长度来存字母与出现次数的映射关系。