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

posted @ 2020-09-13 21:16  童年の波鞋  阅读(126)  评论(0编辑  收藏  举报