2024/08/19 每日一题

XuGui / 2024-08-23 / 原文

LeetCode 552 学生出勤记录II

方法1:动态规划

class Solution {
    static int MOD = 1_000_000_007;
    static int MX = 1_000_01;
    static int[][][] dp = new int[MX][2][3];

    static { // 静态代码块
        dp[0][0][0] = 1; // 只有此时合法
        for (int i = 1; i < MX; i++) {
            dp[i][0][0] = add(dp[i - 1][0][0], dp[i - 1][0][1], dp[i - 1][0][2]);
            dp[i][0][1] = dp[i - 1][0][0];
            dp[i][0][2] = dp[i - 1][0][1];
            dp[i][1][0] = add(dp[i][0][0], dp[i - 1][1][0], dp[i - 1][1][1], dp[i - 1][1][2]);
            // dp[i][1][0] = dp[i - 1][0][0] + dp[i - 1][0][1] + dp[i - 1][0][2] + dp[i - 1][1][0] + dp[i - 1][1][1] + dp[i - 1][1][2];
            dp[i][1][1] = dp[i - 1][1][0];
            dp[i][1][2] = dp[i - 1][1][1];
        }
    }

    static int add(int... nums) {
        int res = nums[0];
        for (int i = 1; i < nums.length; i++) 
            res = (res + nums[i]) % MOD;
        return res;
    }

    public int checkRecord(int n) {
        int ans = 0;
        for (int j = 0; j <= 1; j++) {
            for (int k = 0; k <= 2; k++) {
                ans = (ans + dp[n][j][k]) % MOD;
            }
        }
        return ans;
    }
}

方法2:动态规划 + 快速幂优化

class Solution {
    static int MOD = 1_000_000_007;
    static int length = 6;

    public int checkRecord(int n) {
        int[][] mat = { {1, 1, 1, 0, 0, 0},
                        {1, 0, 0, 0, 0, 0},
                        {0, 1, 0, 0, 0, 0},
                        {1, 1, 1, 1, 1, 1},
                        {0, 0, 0, 1, 0, 0},
                        {0, 0, 0, 0, 1, 0} };
        return qpow(mat, n); // 第一列求和
    }

    static int qpow(int[][] mat, int n) {
        int[][] res = new int[length][length];
        for (int i = 0; i < length; i++) res[i][i] = 1;
        while (n > 0) {
            if ((n & 1) == 1)
                res = multiply(res, mat);
            mat = multiply(mat, mat);
            n >>= 1;
        }
        int ans = 0;
        for (int i = 0; i < length; i++) ans = (ans + res[i][0]) % MOD;
        return ans;
    }

    static int[][] multiply(int[][] arr1, int[][] arr2) {
        int[][] arr = new int[length][length];
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < length; j++) {
                for (int k = 0; k < length; k++) {
                    // 保证相乘不会越界
                    arr[i][j] += mul(arr1[i][k], arr2[k][j]);
                    arr[i][j] %= MOD; // 保证后续相加不越界
                }
            }
        }
        return arr;
    }

    static int mul(int num1, int num2) {
        int res = 0;
        while (num2 > 0) {
            if ((num2 & 1) == 1)
                res = (res + num1) % MOD;
            num1 = (num1 + num1) % MOD;
            num2 >>= 1;
        }
        return res;
    }
}