【LeetCode】424. 替換後的最長重複字元

Curryxin 發表於 2021-08-12
LeetCode

424. 替換後的最長重複字元

知識點:字串,滑動視窗

題目描述

給你一個僅由大寫英文字母組成的字串,你可以將任意位置上的字元替換成另外的字元,總共可最多替換 k 次。在執行上述操作後,找到包含重複字母的最長子串的長度。

注意:字串長度 和 k 不會超過 104。

示例
輸入:s = "ABAB", k = 2
輸出:4
解釋:用兩個'A'替換為兩個'B',反之亦然。

輸入:s = "AABABBA", k = 1
輸出:4
解釋:
將中間的一個'A'替換為'B',字串變為 "AABBBBA"。
子串 "BBBB" 有最長重複字母, 答案為 4。

解法一:滑動視窗

這道題其實挺複雜的,裡面有一些細節很難想;
想一下滑動視窗模板:
這道題目的條件時什麼:當前視窗裡出現次數最多的字母+k等於視窗長度
當達到這個條件後,如果下一個字元不是出現最多的字元,那左視窗就要移動了。
所以我們需要一個變數來記錄當前視窗哪個字母出現的最大次數

class Solution {
    public int characterReplacement(String s, int k) {
        int[] num = new int[26];
        int n = s.length();
        int maxn = 0;
        int left = 0, right = 0;
        while (right < n) {
            int indexR = s.charAt(right) - 'A';
            num[indexR]++;
            //求視窗中曾出現某字母的最大次數
            //計算某字母出現在某視窗中的最大次數,視窗長度只能增大或者不變
            //這樣做的意義:我們求的是最長,如果找不到更長的維持長度不變返回結果不受影響
            maxn = Math.max(maxn, num[indexR]);
            //如果選擇了maxn,那說明又多消耗了一個k;檢查一下k還夠不夠用了,不夠用的話整體移動,注意視窗大小是不變的。   
            //長度len=right-left+1,以下簡稱len
            //len>字母出現最大次數+替換數目,說明k不夠用了,這時候得把視窗向左移;
            //分析一下,替換數目是不變的=k,字母出現最大次數是可能變化的,因此,只有字母出現最大次數增加的情況,len才能拿到最大值
            //left和right一起移動,len不變的
            if (right - left + 1 - maxn > k) {
                //這裡要減的,因為left越過該點,會對最大值有影響
                num[s.charAt(left) - 'A']--;
                left++;
            }
            //走完這裡的時候,其實right會多走一步
            right++;
        }
        //因為right多走一步,結果為(right-1)-left+1==right-left
        return right - left;
    }
}   

細節:

  • 1.num中存的是什麼:num中放的是當前視窗中各字母的長度,所以當我們將左邊界移動的時候,要把左邊界那個移出去的元素次數-1;
  • 2.maxn這個變數:要注意maxn這個變數是在維持一個歷史視窗中的最大值。為什麼維持一個歷史最大值,而不是當前視窗,從根本原因就在於視窗是隻增不減的;如果遍歷到的right能夠不消耗k,那就可以right++,繼續視窗擴張;如果遍歷到的right更多的消耗了k,那就要看消耗後k還夠不夠用了,要是不夠用了,那把整個視窗進行滑動,這時的視窗大小不變;

比如一個子串k=2,然後有一段他的最大重複個數maxn是4,這時候他的長度是6,然後移動滑動視窗到另一段,如果這一串的最大重複個數小於4,那一定不會得到一個大於6的結果,所以記錄歷史最大值是可以了。記住我們找的是最長,如果找不到更長,那就維持不變就可以了

相關連結

替換後的最長重複字元