【刷穿LeetCode系列】LCP 19.秋叶收集器 --- 动态规划题解

本文分享了如何通过状态转移方程解决LeetCode中一道关于调整叶子颜色的LCP题目。通过定义dp数组和isYellow/isRed变量,作者详细阐述了如何找到最小调整次数,确保叶子按【红黄红】顺序排列。代码实现及优化建议也在文中给出。
摘要由CSDN通过智能技术生成
写在前面

大家好我是秋刀鱼,今天刷力扣时做了一道LCP的题目。有刷过LCP的小伙伴一定知道LCP题目向来都是不当人的难😭,中等难度基本上就碾压LeetCode中大部分困难题目。这道题解题思路非常巧妙,给大家分享一下。

LCP 19.秋叶收集器⭐️⭐️⭐️⭐️

题目传送门🚀

image-20211217185110069

1、题目解析

题目要求的是将收集到的红叶、黄叶按照 【红、黄、红】的顺序整理为三个部分,每个部分至少有一片叶子。同时能够调整任意一片叶子的颜色。

不难得知,整理为下面的状态时,叶子的排列顺序符合题意:

image-20211217190050294

整理完毕后叶子的颜色排列一定是 红色黄色红色,不妨我们定义每片叶子所处的状态:

  • 状态一:处于开始的红色部分
  • 状态二:处于黄色部分
  • 状态三:处于结束的红色部分

现在每一片🍁都有了自己的状态,同时每一片🍁最终处于的状态都有可能是这三种状态之一。

但是为了满足题意,每一个颜色块的🍁数量至少为1,也就是说最边缘叶子的状态我们是能够知道的,一定是红色的。

定义状态

定义数组 d p [ i ] [ j ] dp[i][j] dp[i][j] 存储索引位置为 i i i 的叶子,处于 j j j 状态下的最小调整次数。同时定义 isYellow、isRed 布尔类型变量判断第 i i i 位叶子是否为黄色、红色,如果是则值为1。

j = 0 表示状态1,j = 1 表示状态2,j = 2 表示状态 3

状态转移

现在我们开始梳理状态转移方程:

  • 情况一:如果当前叶子颜色最终处于状态一,当前叶子、该叶子的前一片叶子,一定是红色。同时:当前叶子如果不是红色就需要将黄色替换为红色(isYellow==true)。

d p [ i ] [ 0 ] = d p [ i − 1 ] [ 0 ] + i s Y e l l o w dp[i] [0]=dp[i-1] [0]+isYellow dp[i][0]=dp[i1][0]+isYellow

  • 情况二:如果当前叶子颜色最终处于状态二,当前这片🍁一定是黄色,如果为红色则需要调整。但是前一片叶子可能是黄色或红色,也就是说可能处于状态一、状态而。为了调整次数的最小,选择这两种调整状态的最小修改次数调整该位状态:

d p [ i ] [ 1 ] = M a t h . m i n ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] ) + i s R e d dp[i][1] = Math.min(dp[i-1][0],dp[i-1][1])+isRed dp[i][1]=Math.min(dp[i1][0],dp[i1][1])+isRed

  • 情况三:如果当前状态为状态三,该位只能是红色,前一个状态为状态二或状态三,与状态二转移方程类似:

d p [ i ] [ 2 ] = M a t h . m i n ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 2 ] ) + i s Y e l l o w dp[i][2]=Math.min(dp[i-1][1],dp[i-1][2])+isYellow dp[i][2]=Math.min(dp[i1][1],dp[i1][2])+isYellow

返回结果

因为最后一片🍁的状态一定是状态三,因此 d p [ n − 1 ] [ 2 ] dp[n-1][2] dp[n1][2] 一定是题目所求的值。

2、代码部分

class Solution {
    public int minimumOperations(String leaves) {
        int n=leaves.length();
        int [][]dp=new int[n][3];
        dp[0][0]=leaves.charAt(0)=='y'?1:0;
        int MAX=Integer.MAX_VALUE/2;
        dp[0][1]=MAX;
        dp[0][2]=MAX;
        for(int i=1;i<n;++i){
            char cur=leaves.charAt(i);
            int isYellow=cur=='y'?1:0;
            int isRed=cur=='r'?1:0;
            dp[i][0]=dp[i-1][0]+isYellow;
            dp[i][1]=Math.min(dp[i-1][0],dp[i-1][1])+isRed;
            dp[i][2]=Math.min(dp[i-1][1],dp[i-1][2])+isYellow;
        }
        return dp[n-1][2];
    }
}

批注:该写法可被优化为一维形式

写在最后

代码、论述中有任何问题,欢迎大家指出,同时如果有任何疑问,也能够在评论区中留言,大家共同讨论共同进步!

如果觉得博主写的不错的话,可以点赞支持一下!

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋刀鱼与猫_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值