力扣算法篇:学生出勤记录II

在这里插入图片描述
题解:
动态规划的状态由总天数、缺勤次数和结尾连续迟到次数决定
动态规划五部曲:
1、确定dp数组及其下标含义
dp[i][j][k]:前i天有j个‘A’且结尾有连续k个‘L’的可奖励的出勤记录的数量,其中0<=i<=n,0<=j<=1,0<=k<=2;
2、确定递推式
由dp[i-1][][]和第i天的出勤记录推dp[i][][]
如果第i天的出勤记录为‘P’,则前i天与前i-1天相比,A的数量不变,结尾连续L的数量归0

dp[i][j][0] += dp[i-1][j][k](k从02)

如果第i天的出勤记录为A,则前i天与前i-1天相比,A的数量加1,结尾连续L的数量归零,此时要求前i-1天的出勤记录中A的数量必须为0,否则前i天的出勤记录至少有两个A,不满足奖励条件

dp[i][1][0] += dp[i-1][0][k](k从02)

如果第i天的出勤记录为L,则前i天与前i-1天相比,A的数量不变,结尾连续L的数量加1,此时要求前i-1天的出勤记录中结尾连续L的数量小于2,否则会出现结尾连续三个L

dp[i][j][k] += dp[i-1][j][k-1]

3、初始化

dp[0][0][0] = 1;

4、确定遍历顺序
遍历记录的长度,根据第i天的出勤记录依次计算dp
5、举例推导dp
暂不做推导

class Solution {
public:
    static constexpr int MOD = 1'000'000'007;
    int checkRecord(int n) {
        //动态规划 三维dp数组
        vector<vector<vector<int>>> dp(n+1,vector<vector<int>>(2,vector<int>(3,0)));
        //初始化
        dp[0][0][0] = 1;
        for(int i = 1;i<=n;i++){
            //第i天出勤记录为P
            for(int j = 0;j<2;j++){
                for(int k = 0;k<3;k++){
                    dp[i][j][0] = (dp[i][j][0]+dp[i-1][j][k])%MOD;
                }
            }
            //第i天出勤记录为A
            for(int k = 0;k<3;k++){
                dp[i][1][0] = (dp[i][1][0]+dp[i-1][0][k])%MOD;
            }
            //第i天出勤记录为L
            for(int j = 0;j<2;j++){
                for(int k = 1;k<3;k++){
                    dp[i][j][k] = (dp[i][j][k]+dp[i-1][j][k-1])%MOD;
                }
            }
        }
        //求和 dp[n][][]的和
        int sum = 0;
        for(int j = 0;j<2;j++){
            for(int k = 0;k<3;k++){
                sum = (sum+dp[n][j][k])%MOD;
            }
        }
        return sum;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值