列表

详情


552. 学生出勤记录 II

可以用字符串表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤、迟到、到场)。记录中只含下面三种字符:

如果学生能够 同时 满足下面两个条件,则可以获得出勤奖励:

给你一个整数 n ,表示出勤记录的长度(次数)。请你返回记录长度为 n 时,可能获得出勤奖励的记录情况 数量 。答案可能很大,所以返回对 109 + 7 取余 的结果。

 

示例 1:

输入:n = 2
输出:8
解释:
有 8 种长度为 2 的记录将被视为可奖励:
"PP" , "AP", "PA", "LP", "PL", "AL", "LA", "LL" 
只有"AA"不会被视为可奖励,因为缺勤次数为 2 次(需要少于 2 次)。

示例 2:

输入:n = 1
输出:3

示例 3:

输入:n = 10101
输出:183236316

 

提示:

相似题目

学生出勤记录 I

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int checkRecord(int n) { } };

rust 解法, 执行用时: 375 ms, 内存消耗: 27.7 MB, 提交时间: 2024-08-19 09:41:35

impl Solution {
    pub fn check_record(n: i32) -> i32 {
        fn dfs(i: i32, n: i32, s: &mut Vec<char>, cnt_a: i32, sec_l: i32, mem: &mut Vec<Vec<Vec<i32>>>) -> i32 {
            if s.len() as i32 == n { return 1; }
            if mem[i as usize][cnt_a as usize][sec_l as usize] > -1 { return mem[i as usize][cnt_a as usize][sec_l as usize]; }

            let _mod = 1000000007;
            let mut sum = 0;

            s.push('P');
            sum += dfs(i + 1, n, s, cnt_a, 0, mem);
            sum = sum % _mod;
            s.pop();

            if cnt_a < 1 {
                s.push('A');
                sum += dfs(i + 1, n, s, cnt_a + 1, 0, mem);
                sum = sum % _mod;
                s.pop();
            }

            if sec_l < 2 {
                s.push('L');
                sum += dfs(i + 1, n, s, cnt_a, sec_l + 1, mem);
                sum = sum % _mod;
                s.pop();
            }
            mem[i as usize][cnt_a as usize][sec_l as usize] = sum;
            sum
        }
        dfs(0, n, &mut Vec::new(), 0, 0, &mut vec![vec![vec![-1; 3]; 2]; n as usize])
    }
}

python3 解法, 执行用时: 80 ms, 内存消耗: 16 MB, 提交时间: 2023-09-21 10:51:14

class Solution:
    # 矩阵快速幂
    def checkRecord(self, n: int) -> int:
        MOD = 10**9 + 7
        mat = [
            [1, 1, 0, 1, 0, 0],
            [1, 0, 1, 1, 0, 0],
            [1, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 0],
            [0, 0, 0, 1, 0, 1],
            [0, 0, 0, 1, 0, 0],
        ]
        
        def multiply(a: List[List[int]], b: List[List[int]]) -> List[List[int]]:
            rows, columns, temp = len(a), len(b[0]), len(b)
            c = [[0] * columns for _ in range(rows)]
            for i in range(rows):
                for j in range(columns):
                    for k in range(temp):
                        c[i][j] += a[i][k] * b[k][j]
                        c[i][j] %= MOD
            return c
        
        def matrixPow(mat: List[List[int]], n: int) -> List[List[int]]:
            ret = [[1, 0, 0, 0, 0, 0]]
            while n > 0:
                if (n & 1) == 1:
                    ret = multiply(ret, mat)
                n >>= 1
                mat = multiply(mat, mat)
            return ret

        res = matrixPow(mat, n)
        ans = sum(res[0])
        return ans % MOD
        
    # 三维 dp 
    def checkRecord1(self, n: int) -> int:
        MOD = 10**9 + 7
        # 长度,A 的数量,结尾连续 L 的数量
        dp = [[[0, 0, 0], [0, 0, 0]] for _ in range(n + 1)]
        dp[0][0][0] = 1

        for i in range(1, n + 1):
            # 以 P 结尾的数量
            for j in range(0, 2):
                for k in range(0, 3):
                    dp[i][j][0] = (dp[i][j][0] + dp[i - 1][j][k]) % MOD
            
            # 以 A 结尾的数量
            for k in range(0, 3):
                dp[i][1][0] = (dp[i][1][0] + dp[i - 1][0][k]) % MOD
            
            # 以 L 结尾的数量
            for j in range(0, 2):
                for k in range(1, 3):
                    dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j][k - 1]) % MOD
        
        total = 0
        for j in range(0, 2):
            for k in range(0, 3):
                total += dp[n][j][k]
        
        return total % MOD

    # 优化dp
    def checkRecord2(self, n: int) -> int:
        MOD = 10**9 + 7
        # A 的数量,结尾连续 L 的数量
        dp = [[0, 0, 0], [0, 0, 0]]
        dp[0][0] = 1

        for i in range(1, n + 1):
            dpNew = [[0, 0, 0], [0, 0, 0]]

            # 以 P 结尾的数量
            for j in range(0, 2):
                for k in range(0, 3):
                    dpNew[j][0] = (dpNew[j][0] + dp[j][k]) % MOD
            
            # 以 A 结尾的数量
            for k in range(0, 3):
                dpNew[1][0] = (dpNew[1][0] + dp[0][k]) % MOD
            
            # 以 L 结尾的数量
            for j in range(0, 2):
                for k in range(1, 3):
                    dpNew[j][k] = (dpNew[j][k] + dp[j][k - 1]) % MOD
            
            dp = dpNew
        
        total = 0
        for j in range(0, 2):
            for k in range(0, 3):
                total += dp[j][k]
        
        return total % MOD

golang 解法, 执行用时: 0 ms, 内存消耗: 1.8 MB, 提交时间: 2023-09-21 10:49:50

func checkRecord1(n int) (ans int) {
    const mod int = 1e9 + 7
    dp := make([][2][3]int, n+1) // 三个维度分别表示:长度,A 的数量,结尾连续 L 的数量
    dp[0][0][0] = 1
    for i := 1; i <= n; i++ {
        // 以 P 结尾的数量
        for j := 0; j <= 1; j++ {
            for k := 0; k <= 2; k++ {
                dp[i][j][0] = (dp[i][j][0] + dp[i-1][j][k]) % mod
            }
        }
        // 以 A 结尾的数量
        for k := 0; k <= 2; k++ {
            dp[i][1][0] = (dp[i][1][0] + dp[i-1][0][k]) % mod
        }
        // 以 L 结尾的数量
        for j := 0; j <= 1; j++ {
            for k := 1; k <= 2; k++ {
                dp[i][j][k] = (dp[i][j][k] + dp[i-1][j][k-1]) % mod
            }
        }
    }
    for j := 0; j <= 1; j++ {
        for k := 0; k <= 2; k++ {
            ans = (ans + dp[n][j][k]) % mod
        }
    }
    return ans
}

// 优化
func checkRecord2(n int) (ans int) {
    const mod int = 1e9 + 7
    dp := [2][3]int{} // A 的数量,结尾连续 L 的数量
    dp[0][0] = 1
    for i := 1; i <= n; i++ {
        dpNew := [2][3]int{}
        // 以 P 结尾的数量
        for j := 0; j <= 1; j++ {
            for k := 0; k <= 2; k++ {
                dpNew[j][0] = (dpNew[j][0] + dp[j][k]) % mod
            }
        }
        // 以 A 结尾的数量
        for k := 0; k <= 2; k++ {
            dpNew[1][0] = (dpNew[1][0] + dp[0][k]) % mod
        }
        // 以 L 结尾的数量
        for j := 0; j <= 1; j++ {
            for k := 1; k <= 2; k++ {
                dpNew[j][k] = (dpNew[j][k] + dp[j][k-1]) % mod
            }
        }
        dp = dpNew
    }
    for j := 0; j <= 1; j++ {
        for k := 0; k <= 2; k++ {
            ans = (ans + dp[j][k]) % mod
        }
    }
    return ans
}

// 矩阵快速幂
const mod int = 1e9 + 7

type matrix [6][6]int

func (a matrix) mul(b matrix) matrix {
    c := matrix{}
    for i, row := range a {
        for j := range b[0] {
            for k, v := range row {
                c[i][j] = (c[i][j] + v*b[k][j]) % mod
            }
        }
    }
    return c
}

func (a matrix) pow(n int) matrix {
    res := matrix{}
    for i := range res {
        res[i][i] = 1
    }
    for ; n > 0; n >>= 1 {
        if n&1 > 0 {
            res = res.mul(a)
        }
        a = a.mul(a)
    }
    return res
}

func checkRecord(n int) (ans int) {
    m := matrix{
        {1, 1, 0, 1, 0, 0},
        {1, 0, 1, 1, 0, 0},
        {1, 0, 0, 1, 0, 0},
        {0, 0, 0, 1, 1, 0},
        {0, 0, 0, 1, 0, 1},
        {0, 0, 0, 1, 0, 0},
    }
    res := m.pow(n)
    for _, v := range res[0] {
        ans = (ans + v) % mod
    }
    return ans
}

javascript 解法, 执行用时: 116 ms, 内存消耗: 46.6 MB, 提交时间: 2023-09-21 10:48:33

/**
 * @param {number} n
 * @return {number}
 */
var checkRecord1 = function(n) {
    const MOD = 1000000007;
    const dp = new Array(n + 1).fill(2).map(() => new Array(2).fill(0).map(() => new Array(3).fill(0))); // 长度,A 的数量,结尾连续 L 的数量
    dp[0][0][0] = 1;
    for (let i = 1; i <= n; i++) {
        // 以 P 结尾的数量
        for (let j = 0; j <= 1; j++) {
            for (let k = 0; k <= 2; k++) {
                dp[i][j][0] = (dp[i][j][0] + dp[i - 1][j][k]) % MOD;
            }
        }
        // 以 A 结尾的数量
        for (let k = 0; k <= 2; k++) {
            dp[i][1][0] = (dp[i][1][0] + dp[i - 1][0][k]) % MOD;
        }
        // 以 L 结尾的数量
        for (let j = 0; j <= 1; j++) {
            for (let k = 1; k <= 2; k++) {
                dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j][k - 1]) % MOD;
            }
        }
    }
    let sum = 0;
    for (let j = 0; j <= 1; j++) {
        for (let k = 0; k <= 2; k++) {
            sum = (sum + dp[n][j][k]) % MOD;
        }
    }
    return sum;
};

// 优化
var checkRecord2 = function(n) {
    const MOD = 1000000007;
    let dp = new Array(2).fill(0).map(() => new Array(3).fill(0)); // A 的数量,结尾连续 L 的数量
    dp[0][0] = 1;
    for (let i = 1; i <= n; i++) {
        const dpNew = new Array(2).fill(0).map(() => new Array(3).fill(0));
        // 以 P 结尾的数量
        for (let j = 0; j <= 1; j++) {
            for (let k = 0; k <= 2; k++) {
                dpNew[j][0] = (dpNew[j][0] + dp[j][k]) % MOD;
            }
        }
        // 以 A 结尾的数量
        for (let k = 0; k <= 2; k++) {
            dpNew[1][0] = (dpNew[1][0] + dp[0][k]) % MOD;
        }
        // 以 L 结尾的数量
        for (let j = 0; j <= 1; j++) {
            for (let k = 1; k <= 2; k++) {
                dpNew[j][k] = (dpNew[j][k] + dp[j][k - 1]) % MOD;
            }
        }
        dp = dpNew;
    }
    let sum = 0;
    for (let j = 0; j <= 1; j++) {
        for (let k = 0; k <= 2; k++) {
            sum = (sum + dp[j][k]) % MOD;
        }
    }
    return sum;
};

// 矩阵快速幂
var checkRecord = function(n) {
    const MOD = BigInt(1000000007);
    
    const pow = (mat, n) => {
        let ret = [[1, 0, 0, 0, 0, 0]];
        while (n > 0) {
            if ((n & 1) === 1) {
                ret = multiply(ret, mat);
            }
            n >>= 1;
            mat = multiply(mat, mat);
        }
        return ret;
    }

    const multiply = (a, b) => {
        const rows = a.length, columns = b[0].length, temp = b.length;
        const c = new Array(rows).fill(0).map(() => new Array(columns).fill(BigInt(0)));
        for (let i = 0; i < rows; i++) {
            for (let j = 0; j < columns; j++) {
                for (let k = 0; k < temp; k++) {
                    c[i][j] += BigInt(BigInt(a[i][k]) * BigInt(b[k][j]));
                    c[i][j] %= MOD;
                }
            }
        }
        return c;
    }

    const mat = [[1, 1, 0, 1, 0, 0],
                 [1, 0, 1, 1, 0, 0],
                 [1, 0, 0, 1, 0, 0],
                 [0, 0, 0, 1, 1, 0],
                 [0, 0, 0, 1, 0, 1],
                 [0, 0, 0, 1, 0, 0]];
    const res = pow(mat, n);
    const sum = BigInt(eval(res[0].join("+")));
    return sum % MOD;
};

cpp 解法, 执行用时: 4 ms, 内存消耗: 8.3 MB, 提交时间: 2023-09-21 10:47:17

class Solution {
public:
    static constexpr int MOD = 1'000'000'007;

    int checkRecord1(int n) {
        vector<vector<vector<int>>> dp(n + 1, vector<vector<int>>(2, vector<int>(3)));  // 长度,A 的数量,结尾连续 L 的数量
        dp[0][0][0] = 1;
        for (int i = 1; i <= n; i++) {
            // 以 P 结尾的数量
            for (int j = 0; j <= 1; j++) {
                for (int k = 0; k <= 2; k++) {
                    dp[i][j][0] = (dp[i][j][0] + dp[i - 1][j][k]) % MOD;
                }
            }
            // 以 A 结尾的数量
            for (int k = 0; k <= 2; k++) {
                dp[i][1][0] = (dp[i][1][0] + dp[i - 1][0][k]) % MOD;
            }
            // 以 L 结尾的数量
            for (int j = 0; j <= 1; j++) {
                for (int k = 1; k <= 2; k++) {
                    dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j][k - 1]) % MOD;
                }
            }
        }
        int sum = 0;
        for (int j = 0; j <= 1; j++) {
            for (int k = 0; k <= 2; k++) {
                sum = (sum + dp[n][j][k]) % MOD;
            }
        }
        return sum;
    }
    
    // 优化
    int checkRecord2(int n) {
        int dp[2][3];  // A 的数量,结尾连续 L 的数量
        memset(dp, 0, sizeof(dp));
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            int dpNew[2][3];  // A 的数量,结尾连续 L 的数量
            memset(dpNew, 0, sizeof(dpNew));
            // 以 P 结尾的数量
            for (int j = 0; j <= 1; j++) {
                for (int k = 0; k <= 2; k++) {
                    dpNew[j][0] = (dpNew[j][0] + dp[j][k]) % MOD;
                }
            }
            // 以 A 结尾的数量
            for (int k = 0; k <= 2; k++) {
                dpNew[1][0] = (dpNew[1][0] + dp[0][k]) % MOD;
            }
            // 以 L 结尾的数量
            for (int j = 0; j <= 1; j++) {
                for (int k = 1; k <= 2; k++) {
                    dpNew[j][k] = (dpNew[j][k] + dp[j][k - 1]) % MOD;
                }
            }
            memcpy(dp, dpNew, sizeof(dp));
        }
        int sum = 0;
        for (int j = 0; j <= 1; j++) {
            for (int k = 0; k <= 2; k++) {
                sum = (sum + dp[j][k]) % MOD;
            }
        }
        return sum;
    }

    vector<vector<long>> pow(vector<vector<long>> mat, int n) {
        vector<vector<long>> ret = {{1, 0, 0, 0, 0, 0}};
        while (n > 0) {
            if ((n & 1) == 1) {
                ret = multiply(ret, mat);
            }
            n >>= 1;
            mat = multiply(mat, mat);
        }
        return ret;
    }

    vector<vector<long>> multiply(vector<vector<long>> a, vector<vector<long>> b) {
        int rows = a.size(), columns = b[0].size(), temp = b.size();
        vector<vector<long>> c(rows, vector<long>(columns));
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                for (int k = 0; k < temp; k++) {
                    c[i][j] += a[i][k] * b[k][j];
                    c[i][j] %= MOD;
                }
            }
        }
        return c;
    }
    
    // 矩阵快速幂
    int checkRecord(int n) {
        vector<vector<long>> mat = {{1, 1, 0, 1, 0, 0}, {1, 0, 1, 1, 0, 0}, {1, 0, 0, 1, 0, 0}, {0, 0, 0, 1, 1, 0}, {0, 0, 0, 1, 0, 1}, {0, 0, 0, 1, 0, 0}};
        vector<vector<long>> res = pow(mat, n);
        long sum = accumulate(res[0].begin(), res[0].end(), 0ll);
        return (int)(sum % MOD);
    }
};

java 解法, 执行用时: 3 ms, 内存消耗: 38.4 MB, 提交时间: 2023-09-21 10:45:23

class Solution {
    static final int MOD = 1000000007;
    
    public int checkRecord1(int n) {
        // dp[i][j][k] 表示前 i 天有 j 个 ‘A’ 且结尾有连续 k 个 ‘L’ 的可奖励的出勤记录的数量
        int[][][] dp = new int[n + 1][2][3]; // 长度,A 的数量,结尾连续 L 的数量
        dp[0][0][0] = 1;
        for (int i = 1; i <= n; i++) {
            // 以 P 结尾的数量
            for (int j = 0; j <= 1; j++) {
                for (int k = 0; k <= 2; k++) {
                    dp[i][j][0] = (dp[i][j][0] + dp[i - 1][j][k]) % MOD;
                }
            }
            // 以 A 结尾的数量
            for (int k = 0; k <= 2; k++) {
                dp[i][1][0] = (dp[i][1][0] + dp[i - 1][0][k]) % MOD;
            }
            // 以 L 结尾的数量
            for (int j = 0; j <= 1; j++) {
                for (int k = 1; k <= 2; k++) {
                    dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j][k - 1]) % MOD;
                }
            }
        }
        int sum = 0;
        for (int j = 0; j <= 1; j++) {
            for (int k = 0; k <= 2; k++) {
                sum = (sum + dp[n][j][k]) % MOD;
            }
        }
        return sum;
    }
    
    // dp[i][][] 只会从dp[i-1][][] 转移,因此可以将 dp 中的总天数的维度省略
    public int checkRecord2(int n) {
        int[][] dp = new int[2][3]; // A 的数量,结尾连续 L 的数量
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            int[][] dpNew = new int[2][3];
            // 以 P 结尾的数量
            for (int j = 0; j <= 1; j++) {
                for (int k = 0; k <= 2; k++) {
                    dpNew[j][0] = (dpNew[j][0] + dp[j][k]) % MOD;
                }
            }
            // 以 A 结尾的数量
            for (int k = 0; k <= 2; k++) {
                dpNew[1][0] = (dpNew[1][0] + dp[0][k]) % MOD;
            }
            // 以 L 结尾的数量
            for (int j = 0; j <= 1; j++) {
                for (int k = 1; k <= 2; k++) {
                    dpNew[j][k] = (dpNew[j][k] + dp[j][k - 1]) % MOD;
                }
            }
            dp = dpNew;
        }
        int sum = 0;
        for (int j = 0; j <= 1; j++) {
            for (int k = 0; k <= 2; k++) {
                sum = (sum + dp[j][k]) % MOD;
            }
        }
        return sum;
    }

    // 矩阵快速幂
    public int checkRecord(int n) {
        long[][] mat = {{1, 1, 0, 1, 0, 0},
                        {1, 0, 1, 1, 0, 0},
                        {1, 0, 0, 1, 0, 0},
                        {0, 0, 0, 1, 1, 0},
                        {0, 0, 0, 1, 0, 1},
                        {0, 0, 0, 1, 0, 0}};
        long[][] res = pow(mat, n);
        long sum = Arrays.stream(res[0]).sum();
        return (int) (sum % MOD);
    }

    public long[][] pow(long[][] mat, int n) {
        long[][] ret = {{1, 0, 0, 0, 0, 0}};
        while (n > 0) {
            if ((n & 1) == 1) {
                ret = multiply(ret, mat);
            }
            n >>= 1;
            mat = multiply(mat, mat);
        }
        return ret;
    }

    public long[][] multiply(long[][] a, long[][] b) {
        int rows = a.length, columns = b[0].length, temp = b.length;
        long[][] c = new long[rows][columns];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                for (int k = 0; k < temp; k++) {
                    c[i][j] += a[i][k] * b[k][j];
                    c[i][j] %= MOD;
                }
            }
        }
        return c;
    }
}

上一题