LCP 19.秋叶收藏集 动态规划

题目链接:https://leetcode-cn.com/problems/UlBDOe/
在这里插入图片描述
在这里插入图片描述

  • 这道题拿到手上,直接懵了,感觉dp、贪心什么的都不对,因为题目好像不存在什么序的关系。

  • 但是,仔细想想,最后一个叶子必然为红色段(如果叶子本身为 y y y,那么肯定要改成 r r r),那么到最后一片叶子前面总共修改了几次,那么就看前 n − 1 n-1 n1片叶子总共修改了几次(此时似乎出现了子结构),但是第 n − 1 n-1 n1片叶子可以是处于阶段2(即 y y y叶子段)、也可以是处于阶段3(即 r r r叶子段)(此时似乎出现了决策(状态转移))。

  • 状态定义:定义成三维
    1、 d p ( i , 0 ) dp(i,0) dp(i,0)表示第 i i i片叶子处于阶段1( r r r叶子段)时,前i片最少需要修改的个数。
    2、 d p ( i , 1 ) dp(i,1) dp(i,1)表示第 i i i片叶子处于阶段2( y y y叶子段)时,前i片最少需要修改的个数。
    3、 d p ( i , 2 ) dp(i,2) dp(i,2)表示第 i i i片叶子处于阶段3( r r r叶子段)时,前i片最少需要修改的个数。

  • 状态转移:根据目前所处的阶段和本身的叶子颜色进行转移:
    1、 d p ( i , 0 ) = d p ( i − 1 , 0 ) + ( l e a [ i ] = = ′ r ′   ?   0 :   1 ) dp(i,0)=dp(i-1,0)+(lea[i]=='r'\ ?\ 0:\ 1) dp(i,0)=dp(i1,0)+(lea[i]==r ? 0: 1)
    2、 d p ( i , 1 ) = m i n ( d p ( i − 1 , 0 ) , d p ( i − 1 , 1 ) ) + ( l e a [ i ] = = ′ r ′   ?   1 :   0 ) dp(i,1)=min(dp(i-1,0),dp(i-1,1))+(lea[i]=='r'\ ?\ 1:\ 0) dp(i,1)=min(dp(i1,0),dp(i1,1))+(lea[i]==r ? 1: 0)(处于阶段2的叶子,前面的第 i − 1 i-1 i1片可以是红叶、也可以是黄叶)
    3、 d p ( i , 2 ) = m i n ( d p ( i − 1 , 1 ) , d p ( i − 1 , 2 ) ) + ( l e a [ i ] = = ′ r ′   ?   0 :   1 ) dp(i,2)=min(dp(i-1,1),dp(i-1,2))+(lea[i]=='r'\ ?\ 0:\ 1) dp(i,2)=min(dp(i1,1),dp(i1,2))+(lea[i]==r ? 0: 1)(处于阶段3的叶子,前面的第 i − 1 i-1 i1片可以是黄叶、也可以是红叶)

  • 初始化(这里至关重要):
    1、 d p ( 0 , 0 ) dp(0,0) dp(0,0)必须是红叶,所以要根据第一片叶子的颜色进行初始化。
    2、因为第一片叶子必须是红叶,所以 d p ( 1 , 1 ) dp(1,1) dp(1,1)必须根据 d p ( 0 , 0 ) dp(0,0) dp(0,0)初始化,即使 l e a [ 1 ] lea[1] lea[1]为黄色, l e a [ 0 ] lea[0] lea[0]为黄色的话, d p ( 1 , 1 ) dp(1,1) dp(1,1)也不可能为0。
    3、同样的, d p ( 2 , 2 ) dp(2,2) dp(2,2)要根据 d p ( 1 , 1 ) dp(1,1) dp(1,1)进行初始化。

  • 递推:
    1、阶段1只需要从第二片叶子开始推,因为第一片叶子肯定是红色。
    2、阶段2只需要从第三片叶子开始推,因为第二片叶子为黄色的时候,已经被初始化了,这样后面递推的时候才不会出错。
    3、阶段3同样只需要从第四片叶子开始推。

const int MAXN = 1e5 + 5;
int dp[MAXN][3];
class Solution {
public:
   // r y r
    int minimumOperations(string leaves) {
        memset(dp, 0, sizeof(dp));
        int n = leaves.length();

        if (leaves[0] == 'r') dp[0][0] = 0;
        else dp[0][0] = 1; 
        for (int i = 1; i < n; i++){
            if (leaves[i] == 'r') dp[i][0] = dp[i - 1][0];
            else dp[i][0] = dp[i - 1][0] + 1;
        }

        if (leaves[1] == 'y') dp[1][1] = dp[0][0];
        else dp[1][1] = dp[0][0] + 1;
        for (int i = 2; i < n; i++){
            if (leaves[i] == 'r') 
                dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]) + 1;
            else dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]);
        }

        if (leaves[2] == 'r') dp[2][2] = dp[1][1];
        else dp[2][2] = dp[1][1] + 1;
        for (int i = 3; i < n; i++){
            if (leaves[i] == 'r')
                dp[i][2] = min(dp[i - 1][1], dp[i - 1][2]);
            else dp[i][2] = min(dp[i - 1][1], dp[i - 1][2]) + 1;
        }
        // 最后 n - 1 必须是状态 3
        return dp[n - 1][2];
    }
};
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值