b_lc_秋葉收集器(分類討論dp+滾動陣列優化)
阿新 • • 發佈:2020-09-13
出於美觀整齊的考慮,小扣想要將收藏集中樹葉的排列調整成「紅、黃、紅」三部分。每部分樹葉數量可以不相等,但均需大於等於 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),
- if (s[i]='r') 時,r 可以修改成 y,也可不修改
- 思考輸出: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...