1. 程式人生 > 實用技巧 >b_lc_秋葉收集器(分類討論dp+滾動陣列優化)

b_lc_秋葉收集器(分類討論dp+滾動陣列優化)

出於美觀整齊的考慮,小扣想要將收藏集中樹葉的排列調整成「紅、黃、紅」三部分。每部分樹葉數量可以不相等,但均需大於等於 1。每次調整操作,小扣可以將一片紅葉替換成黃葉或者將一片黃葉替換成紅葉。請問小扣最少需要多少次調整操作才能將秋葉收藏集調整完畢。

輸入:leaves = "rrryyyrryyyrr"
輸出:2
解釋:調整兩次,將中間的兩片紅葉替換成黃葉,得到 "rrryyyyyyyyrr"
提示:3 <= leaves.length <= 10^5

方法一:dp

目標是將 s 變成 rrr...yyy...rrr...{紅...黃...紅...}

  • 定義狀態
    • f[i][0] 表示序列 0..i 都是r
    • f[i][1] 表示序列 0..i 從r變成了y,且y結尾
    • f[i][2] 表示序列 0..i 從r變成了y,又從y變成了r,且r結尾
  • 思考初始化:
    • f[0][0]=s[0]==r ? 0 : 1
    • f[0][1]=+inf
    • f[0][2]=+inf
  • 思考狀態轉移方程
    • if (s[i]='r') 時,r 可以修改成 y,也可不修改
      • f[i][0]=f[i-1][0]
      • f[i][1]=min(f[i-1][0]+1, f[i-1][1]+1)
      • f[i][2]=min(f[i-1][2], f[i-1][1]),當前就是以 r 結尾,所以只需取到前一個狀態即可
    • if (s[i]='y') 時,y 可以修改成 r,也可不修改
      • f[i][0]=f[i-1][0]+1
      • f[i][1]=min(f[i-1][1], f[i-1][0]),當前就是以 y 結尾,所以只需取 f[i-1][1]/f[i-1][0],這裡沒有 f[i-1][2] 的事,因為需要漸變
      • f[i][2]=min(f[i-1][1]+1, f[i-1][2]+1),
  • 思考輸出:f[n-1][2]
class Solution {
public:
    // rrr...yyy...rrr
    int minimumOperations(string s) {
        if (s.empty()) return 0;
        int n=s.size(), inf=0x3f3f3f3f, f[n+1][3]; 
        memset(f, inf, sizeof f); f[0][0]=0;
        if (s[0]=='y') f[0][0]=1;
        
        for (int i=1; i<n; i++) {
            if (s[i]=='r') {
                f[i][0]=f[i-1][0];
                f[i][1]=min(f[i-1][0], f[i-1][1])+1;
                f[i][2]=min(f[i-1][1], f[i-1][2]);
            } else {
                f[i][0]=f[i-1][0]+1;
                f[i][1]=min(f[i-1][1], f[i-1][0]);
                f[i][2]=min(f[i-1][1], f[i-1][2])+1;
            }
        }
        return f[n-1][2];
    }
};

複雜度分析

  • Time\(O(n)\)
  • Space\(O(n)\)

參考別人的滾動陣列優化解法,相比自己寫的,orz...