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),
- 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...