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

一、問題描述

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

注意:
字符串長度 和 k 不會超過 10^4

示例 1:

輸入:
s = "ABAB", k = 2

輸出:
4

解釋:
用兩個'A'替換爲兩個'B',反之亦然。


示例 2:

輸入:
s = "AABABBA", k = 1

輸出:
4

解釋:
將中間的一個'A'替換爲'B',字符串變爲 "AABBBBA"。
子串 "BBBB" 有最長重複字母, 答案爲 4。

 題目來源:LeetCode   鏈接:https://leetcode-cn.com/problems/longest-repeating-character-replacement

二、解題思路

1.暴力法,一般時間都會超限

class Solution {
public:
    int characterReplacement(string s, int k) {
        int k2=k, maxlen=0, first=s.length();
        int i=0, j=0;                           //一個左邊界i,一個右邊界j
        while(i<s.length()&&j<s.length())
        {
            if(s[j]!=s[i])
            {
                if(k2>0)
                {
                    k2--;
                    first = first< j ? first: j;  //first記錄第一個跟s[i]不相同的元素下標
                                                 //後面可以直接把i重新賦值爲first,而不是i+1
                    j++;
                }
                else                             //如果k次修改機會用完
                {
                    int temp = j-i;
                    maxlen = maxlen<temp?temp:maxlen; //記錄最長字符串長度
                    if((s.length()-first)>maxlen)   //只有first後面的字符串大於目前的maxlen
                    {                               //繼續執行纔有意義,否則直接break
                        i = first;                  //把i賦值爲first
                        j = i+1;                    //j爲i+1
                        k2 = k;                     //k2復原爲原值
                    }
                    else
                        break;
                }
            }
            else
            {
                j++;
            }
            int temp = j-i;
            maxlen = maxlen<temp?temp:maxlen;
        }
        return maxlen;
    }
};

2.滑動窗口法

  上面的暴力法最壞情況了的時間複雜度其實可以達到O(n^2), 這是因爲當k次修改機會用完又遇到跟左邊界值s[i]不同的元素時,採取的策略是往回走,把i賦值爲first,j賦值爲i+1。而滑動窗口的思想就是一直往前滑,爭取達到O(n)的時間複雜度。而這要怎麼才能做到?

  該方法時記錄滑動窗口內的最多個數的字符即charMax,只要滿足right - left + 1 > charMax + k即可繼續向右擴張,即right++,不滿足的時候就窗口整體向右移動,即同時right++,left++。這時候,假設後面都沒有更長的替換後連續字符串的話,那麼這個窗口長度會一直不變,知道循環結束(right走到終點),而如果後面還有更長的替換後連續字符串的話,這個窗口就會再次擴張。最後返回窗口大小,就是所求的替換後最長連續字符串的長度。

class Solution {
public:
    int characterReplacement(string s, int k) {
        if(s.length()==0)
            return 0;
        int map[26]={0};                                       //map用來記錄字符數
        int i=0, charmax=0;                                    //map數組下標爲鍵,內容爲值
        for(int j=0;j<s.length();j++)
        {
            int index = s[j]-'A';
            map[index]++;                                       //向右擴張一步
            charmax=charmax>map[index]?charmax:map[index];      //更新charmax
            if((j-i+1)>charmax+k)
            {
                map[s[i]-'A']--;                                //如果不符合條件,左邊收縮
                                                                //保持窗口長度不變
                i++;
            }
        }
        return s.length()-i;                                    
    }
};

三、總結

    1.滑動窗口通常由擴張、收縮、移動三種行爲,根據解題過程的不同階段採取不同的行爲

    2.滑動窗口經常搭配map使用 ,意在記錄滑動窗口中的信息

    3.滑動窗口很適合解決字符串類的題目

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章