leetcode
leetcode 501 ~ 550
学生出勤记录 II

学生出勤记录 II

难度:

标签:

题目描述

代码结果

运行时间: 126 ms, 内存: 16.0 MB


/*
 * 思路:
 * - 使用流式处理来计算合法出勤记录的数量。
 * - 我们使用一个包含所有可能的长度为 n 的出勤记录的流。
 * - 然后过滤出满足条件的记录:
 *   - 缺勤次数小于 2
 *   - 不存在连续 3 天或以上的迟到记录
 * - 最后统计符合条件的记录数量,并取模 (10^9 + 7)。
 */
 
import java.util.stream.Stream;
 
public class AttendanceRewardStream {
    private static final int MOD = 1000000007;
 
    public int checkRecord(int n) {
        return (int) Stream.generate(() -> new char[n])
                .limit((int) Math.pow(3, n))
                .parallel()
                .map(this::generateRecord)
                .filter(this::isValid)
                .count() % MOD;
    }
 
    private String generateRecord(char[] chars) {
        int index = 0;
        for (int i = 0; i < chars.length; i++) {
            if (index % 3 == 0) chars[i] = 'P';
            else if (index % 3 == 1) chars[i] = 'L';
            else chars[i] = 'A';
            index++;
        }
        return new String(chars);
    }
 
    private boolean isValid(String record) {
        int absentCount = 0;
        int lateStreak = 0;
        for (char c : record.toCharArray()) {
            if (c == 'A') absentCount++;
            if (c == 'L') lateStreak++;
            else lateStreak = 0;
            if (absentCount >= 2 || lateStreak >= 3) return false;
        }
        return true;
    }
}
 

解释

方法:

这个题解使用了矩阵快速幂的方法来解决问题。它定义了一个6个状态的转移矩阵,其中每个状态表示当前的出勤记录状态。通过对转移矩阵进行快速幂运算,可以得到从初始状态经过 n-1 次转移后的各个状态的数量。最后将所有状态的数量相加即可得到答案。为了避免大数问题,过程中的计算都对 10^9+7 取模。

时间复杂度:

O(logn)

空间复杂度:

O(1)

代码细节讲解

🦆
题解中提到的六个状态具体代表什么意义,能否具体解释每个状态所对应的出勤记录类型?
在题解中,六个状态用于描述学生的出勤记录,具体含义如下:状态0代表没有缺席且结尾没有连续迟到(A=0, L=0),状态1代表没有缺席且结尾有一个迟到(A=0, L=1),状态2代表没有缺席且结尾有两个连续迟到(A=0, L=2),状态3代表有一个缺席且结尾没有连续迟到(A=1, L=0),状态4代表有一个缺席且结尾有一个迟到(A=1, L=1),状态5代表有一个缺席且结尾有两个连续迟到(A=1, L=2)。这六个状态覆盖了学生出勤记录中所有可能的有效组合。
🦆
在定义的状态转移矩阵中,矩阵的每个元素具体如何表示状态之间的转移?例如,base[0][1] 和 base[3][4] 分别代表什么意义?
在状态转移矩阵中,每个元素代表从一种状态到另一种状态的转移可能性。例如,base[0][1]的值为1表示状态0(没有缺席且结尾没有连续迟到)可以转移到状态1(没有缺席且结尾有一个迟到),base[3][4]的值为1表示状态3(有一个缺席且结尾没有连续迟到)可以转移到状态4(有一个缺席且结尾有一个迟到)。这些转移表示添加一个新的出勤记录后状态的变化。
🦆
矩阵快速幂在这个问题中的应用是如何确保能够有效计算出 n 天的可能状态数量的?
矩阵快速幂是一种优化矩阵幂运算的算法,适用于当需要计算矩阵的高次幂时。在这个问题中,将出勤状态的转移表示为一个矩阵,然后通过计算这个矩阵的n-1次幂来得到n天后的状态分布。矩阵快速幂通过分治的思想减少运算次数,当n非常大时,普通的矩阵乘法需要进行n-1次乘法,而矩阵快速幂将复杂度降低到log(n)级别,显著提高了效率。
🦆
题解中初始化矩阵 init 的设置是怎样确定的?每个元素的初始值代表什么?
初始化矩阵 init 表示了第一天可能的出勤状态。在这个问题中,init的设置代表了第一天的六种可能状态:[1], [1], [0], [1], [0], [0],分别对应状态0至状态5。这里数值1表示该状态在第一天是可能的,数值0表示不可能。例如,第一天有一个连续迟到(状态2)或有一个连续迟到加一个缺席(状态4和状态5)是不可能的。

相关问题

学生出勤记录 I

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

  • 'A':Absent,缺勤
  • 'L':Late,迟到
  • 'P':Present,到场

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

  • 总出勤 计,学生缺勤('A'严格 少于两天。
  • 学生 不会 存在 连续 3 天或 连续 3 天以上的迟到('L')记录。

如果学生可以获得出勤奖励,返回 true ;否则,返回 false

 

示例 1:

输入:s = "PPALLP"
输出:true
解释:学生缺勤次数少于 2 次,且不存在 3 天或以上的连续迟到记录。

示例 2:

输入:s = "PPALLL"
输出:false
解释:学生最后三天连续迟到,所以不满足出勤奖励的条件。

 

提示:

  • 1 <= s.length <= 1000
  • s[i]'A''L''P'