给定一个正整数 n,返回长度为 n 的所有可被视为可奖励的出勤记录的数量。 答案可能非常大,你只需返回结果mod 109 + 7的值。
学生出勤记录是只包含以下三个字符的字符串:
- 'A' : Absent,缺勤
- 'L' : Late,迟到
- 'P' : Present,到场
如果记录不包含多于一个'A'(缺勤)或超过两个连续的'L'(迟到),则该记录被视为可奖励的。
示例 1:
输入: n = 2 输出: 8 解释: 有8个长度为2的记录将被视为可奖励: "PP" , "AP", "PA", "LP", "PL", "AL", "LA", "LL" 只有"AA"不会被视为可奖励,因为缺勤次数超过一次。
注意:n 的值不会超过100000
================================================
做这个题心态又回来了一些...
解题思路:动态规划
我们以追加的形式来做这道题
定义dp[n][A][L] n为出勤次数, A为A出现的次数(大于2就gg) , L为末尾几个L , 值为多少个
返回 sum(dp[n])就可以了
定义大小 dp[n+1][2][3]
dp[i][0][0]=Sum(dp[i-1][0];
dp[i][1][0]=Sum(dp[i-1][0])+Sum(dp[i-1][1]);
dp[i][0][1]=dp[i-1][0][0];
dp[i][1][1]=dp[i-1][1][0];
dp[i][0][2]=dp[i-1][0][1];
dp[i][1][2]=dp[i-1][1][1];
如果这6个状态固定,我们就可以推倒出 dp[n]
直接贴代码吧
class Solution {
public int checkRecord(int n) {
if (n == 1) {
return 3;
}
int[][] dp = {{2, 1, 1}, {3, 1, 0}};
int mod = 1000000007;
int res = 8;
for (int i = 3; i < n + 1; i++) {
int x10 = dp[1][0];
int x00 = dp[0][0];
dp[1][0] = (sum(dp[0]) + sum(dp[1])) % mod;
dp[0][0] = sum(dp[0]);
dp[1][2] = dp[1][1];
dp[0][2] = dp[0][1];
dp[0][1] = x00;
dp[1][1] = x10;
}
res=(sum(dp[0]) + sum(dp[1])) % mod;
return res;
}
private int sum(int[] arr) {
long res = 0;
for (int p : arr) {
res += p;
}
return (int) (res % 1000000007);
}
}
我做了一些小的优化,优化了空间复杂度为常数级别