学生出勤记录 II -- LeetCode -- 8.18
学生出勤记录
(记忆化DFS 或者 动态规划)
可以用字符串表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤、迟到、到场)。记录中只含下面三种字符:
'A'
:Absent,缺勤'L'
:Late,迟到'P'
:Present,到场
如果学生能够 同时 满足下面两个条件,则可以获得出勤奖励:
- 按 总出勤 计,学生缺勤(
'A'
)严格 少于两天。 - 学生 不会 存在 连续 3 天或 连续 3 天以上的迟到(
'L'
)记录。
给你一个整数 n
,表示出勤记录的长度(次数)。请你返回记录长度为 n
时,可能获得出勤奖励的记录情况 数量 。答案可能很大,所以返回对 10^9 + 7
取余 的结果。
示例 1:
输入:n = 2 输出:8 解释: 有 8 种长度为 2 的记录将被视为可奖励: "PP" , "AP", "PA", "LP", "PL", "AL", "LA", "LL" 只有"AA"不会被视为可奖励,因为缺勤次数为 2 次(需要少于 2 次)。
DFS:
class Solution {
public:
int mod = 1000000007;
//int mod = 10e9 + 7;
int a[100005][2][3];
int dfs(int u, int acnt, int lcnt){
if(acnt >= 2 || lcnt >= 3)return 0;
if(u == 0)return 1;
if(a[u][acnt][lcnt] != -1)return a[u][acnt][lcnt];
int ans = 0;
ans = dfs(u - 1, acnt + 1, 0) % mod;
ans = (ans + dfs(u - 1, acnt, lcnt + 1)) % mod;
ans = (ans + dfs(u - 1, acnt, 0)) % mod;
a[u][acnt][lcnt] = ans;//用于记忆
return ans;
}
int checkRecord(int n) {
for(int i = 0; i <= n; i++){
for(int j = 0; j < 2; j++){
for(int k = 0; k < 3; k++){
a[i][j][k] = -1;
}
}
}
return dfs(n, 0, 0);
}
};
速度一般。
动态规划:
基本上可以说这是通过记忆化的DFS演变过来的。
比如说a[i][0][0] = a[i - 1][0][0] + a[i - 1][0][1] + a[i - 1][0][2];
解:当第 i 天时,还不存在旷课和迟到情况的条件下,只能由一下三种情况推演而来
①当 i - 1天的时候,没有旷课和迟到;a[i - 1][0][0];
②当 i - 1天的时候,没有旷课和一次迟到;a[i - 1][0][1];//这时,咱在第 i 天的时候加上 P(到场) 的话,迟到次数则会情况变为 0;
③当 i - 1天的时候,没有旷课和两次迟到;a[i - 1][0][2];//同理
class Solution { public: int mod = 1000000007; long long a[100005][2][3]; int checkRecord(int n) { a[0][1][0] = 1; a[0][0][0] = 1; a[0][0][1] = 1; for(int i = 1; i < n; i++) { //加入 P a[i][0][0] = (a[i - 1][0][0] + a[i - 1][0][1] + a[i - 1][0][2]) % mod; a[i][1][0] = (a[i - 1][1][0] + a[i - 1][1][1] + a[i - 1][1][2]) % mod; //加入 A a[i][1][0] = (a[i][1][0] + a[i - 1][0][0] + a[i - 1][0][1] + a[i - 1][0][2]) % mod;//这个可以和上面那个合并 //加入 L a[i][0][1] = a[i - 1][0][0] % mod; a[i][0][2] = a[i - 1][0][1] % mod; a[i][1][1] = a[i - 1][1][0] % mod; a[i][1][2] = a[i - 1][1][1] % mod; } long long ans = 0; for(int i = 0; i <= 1; i++){ for(int j = 0; j <= 2; j++){ ans = (ans + a[n - 1][i][j]) % mod; } } cout << ans << endl; return ans; } };
比记忆化DFS快上不少。