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的結果,所以記錄歷史最大值是可以了。記住我們找的是最長,如果找不到更長,那就維持不變就可以了