1234. 替換子字串得到平衡字串

中等 字串 滑動窗口

推薦事前閱讀:滑動窗口

思路

先計算每個字元出現了多少次,出現次數多餘 n/4n/4 的部分需要取代掉。
比如說,現在要求每個字元出現 10 次,而 Q 出現了 12 次,這時就去找一個子字串,裡面要包含兩個 Q,把它替換掉。
Q 佔走的位置會影響到其他字元,只要把找到的子字串換成缺少的字元就行了。以右邊例子而言就是換成 E 和 R。

  • W = 10
  • Q = 12
  • E = 9
  • R = 9

如果有多個字元出現次數比需求的多,要找的字串就會隨之變化,以右邊例子來說,就是要找包含一個W,以及兩個Q的字串。
這樣就跟76. 最小覆蓋子串的做法相同,要找到包含指定字串的最短字串。

  • W = 11
  • Q = 12
  • E = 8
  • R = 9

程式碼

滑動窗口

class Solution {
private:
    int getID(char ch) {
        if(ch == 'Q') return 0;
        else if(ch == 'W') return 1;
        else if(ch == 'E') return 2;
        else if(ch == 'R') return 3;
        return -1;
    }
public:
    int balancedString(string s) {
        int n = s.length();

        // 1. 統計字元出現次數
        int cnt[4]{};        
        for(int i = 0; i < n; ++i) {
            cnt[getID(s[i])]++;
        }
        
        // 2. 債務表更新
        int m = n / 4;
        int debt = 0;
        for(int i = 0; i < 4; i++) {
            cnt[i] = min(0, m - cnt[i]); // 如果比 m 多, 相減是負數, 代表欠,比 m 少會是 0, 代表沒欠
            debt -= cnt[i]; // 如果有欠債, cnt[i] 是負數, 所以用減的
        }
        if(debt == 0) return 0; // 沒有債務,不需要修改字串

        // 3. 找到最短字串
        int res = n;
        for(int i = 0, j = 0; j < n; j++) {
            if(cnt[getID(s[j])]++ < 0) { // 還債 
                debt--; // 還的字元的確是需要的
            }
            if(debt == 0) {
                while(cnt[getID(s[i])] > 0) { // 左邊界的字元有盈餘
                    cnt[getID(s[i++])]--; // 移動左邊界
                }
                res = min(res, j - i + 1);
            }
        }
        return res;
    }
};

複雜度分析

  • 時間複雜度:O(n)O(n)
  • 空間複雜度:O(1)O(1)

顯示設定

背景線條
顯示背景網格線條
懸停發光
滑鼠懸停時顯示霓虹效果
聚光燈
跟隨滑鼠的聚光燈效果
背景透明度
開啟透明玻璃效果
主題顏色
自訂主要顏色