学生出勤记录 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快上不少。

posted @ 2021-08-18 18:05  荣荣荣荣荣荣  阅读(62)  评论(0)    收藏  举报