Leetcode 552. 学生出勤记录 II
题目
给定一个正整数 n,返回长度为 n 的所有可被视为可奖励的出勤记录的数量。 答案可能非常大,你只需返回结果mod 109 + 7的值。
学生出勤记录是只包含以下三个字符的字符串:
- ‘A’ : Absent,缺勤
- ‘L’ : Late,迟到
- ‘P’ : Present,到场
如果记录不包含多于一个’A’(缺勤)或超过两个连续的’L’(迟到),则该记录被视为可奖励的。
示例:
输入: n = 2
输出: 8
解释:
有8个长度为2的记录将被视为可奖励:
"PP" , "AP", "PA", "LP", "PL", "AL", "LA", "LL"
只有"AA"不会被视为可奖励,因为缺勤次数超过一次。
**注意:**n 的值不会超过100000。
题解
动态规划
我们先不考虑有A这种情况,那么dp[n]表示长度为n的可奖励出勤记录
- 假设最后一个记录为P,则只需要保证前几天为可奖励情况,即dp[n-1]
- 假设最后一个记录为L,则 ···L 可以再分为4中情况···LLL、···PLL、···LPL、···PPL,符号奖励记录的也就是dp[n-1]-dp[n-4],即减去···LLL这种情况
故dp[n] = 2*dp[n-1]-dp[n-4]
现在加上A,则A可以出现在1~n的任意一天,如果是第i天缺席,则i-1天要满足奖励情况;后面的n-i天也需要满足奖励情况,也就是说dp[i-1] * dp[n-i]
由上面的转移方程可知,转移方程适用于n>=4的情况,因此我们需要对0~3进行初始化。详细过程见代码
代码
int checkRecord(int n) {
long mod = pow(10,9)+7;
vector<int> dp(n>3 ? n+1 : 5,0);
dp[0] = 1;
dp[1] = 2;
dp[2] = 4;
dp[3] = 7;
for(int i=4; i<=n; i++){
dp[i] = ((2*dp[i-1])%mod + (mod-dp[i-4]))%mod;
}
long sum = dp[n];
for (int i = 1; i <= n; i++) {
sum += ((long)dp[i-1] * dp[n-i])%mod;
sum %= mod;
}
return sum;
}
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/student-attendance-record-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。