{x}
blog image

Student Attendance Record II

An attendance record for a student can be represented as a string where each character signifies whether the student was absent, late, or present on that day. The record only contains the following three characters:

  • 'A': Absent.
  • 'L': Late.
  • 'P': Present.

Any student is eligible for an attendance award if they meet both of the following criteria:

  • The student was absent ('A') for strictly fewer than 2 days total.
  • The student was never late ('L') for 3 or more consecutive days.

Given an integer n, return the number of possible attendance records of length n that make a student eligible for an attendance award. The answer may be very large, so return it modulo 109 + 7.

 

Example 1:

Input: n = 2
Output: 8
Explanation: There are 8 records with length 2 that are eligible for an award:
"PP", "AP", "PA", "LP", "PL", "AL", "LA", "LL"
Only "AA" is not eligible because there are 2 absences (there need to be fewer than 2).

Example 2:

Input: n = 1
Output: 3

Example 3:

Input: n = 10101
Output: 183236316

 

Constraints:

  • 1 <= n <= 105

Solution Explanation:

This problem asks to find the number of possible attendance records of length n that satisfy two conditions:

  1. The number of absences ('A') is strictly less than 2.
  2. There are no 3 or more consecutive late days ('L').

The most efficient approach is using dynamic programming. We can represent the state of the attendance record using a 3-dimensional array:

  • dp[i][j][k] represents the number of attendance records of length i where:
    • j indicates the number of absences (0 or 1).
    • k represents the number of consecutive late days (0, 1, or 2).

Base Cases:

For i = 0, we have:

  • dp[0][0][0] = 1 (empty string)

Recurrence Relation:

For i > 0, we can transition from the previous state (i-1) based on the character added:

  • 'P' (Present): We can add 'P' to any previous state without changing the number of absences or consecutive late days. Thus: dp[i][j][0] += dp[i-1][j][k] (for all k)

  • 'L' (Late): Adding 'L' increases the consecutive late days by 1. If k < 2, we can add 'L': dp[i][j][k+1] += dp[i-1][j][k]

  • 'A' (Absent): Adding 'A' only if j < 1 (less than 2 absences): dp[i][j+1][0] += dp[i-1][j][k] (for all k)

We update the dp array iteratively, taking the modulo 10^9 + 7 to prevent integer overflow. The final answer is the sum of all possible states in dp[n-1].

Time and Space Complexity Analysis:

  • Time Complexity: O(n) - We iterate through n days. The nested loops within the dynamic programming approach are constant time, O(1).
  • Space Complexity: O(n) - The size of the dp array is proportional to n.

Code Implementations (with detailed comments):

Python3:

class Solution:
    def checkRecord(self, n: int) -> int:
        mod = 10**9 + 7
        dp = [[[0, 0, 0], [0, 0, 0]] for _ in range(n)] # Initialize 3D DP array
 
        # Base case: length 0 has one valid record (empty string)
        dp[0][0][0] = 1
 
        for i in range(1, n): # Iterate through lengths
            #Adding 'P'
            dp[i][0][0] = (dp[i - 1][0][0] + dp[i - 1][0][1] + dp[i - 1][0][2]) % mod
            dp[i][1][0] = (dp[i - 1][1][0] + dp[i - 1][1][1] + dp[i - 1][1][2]) % mod
            
            # Adding 'L'
            dp[i][0][1] = dp[i - 1][0][0] # Only if there were no consecutive 'L' before
            dp[i][0][2] = dp[i - 1][0][1] # Only if there were 1 consecutive 'L' before
            dp[i][1][1] = dp[i-1][1][0]
            dp[i][1][2] = dp[i-1][1][1]
 
            #Adding 'A' (only if fewer than 2 'A's)
            dp[i][1][0] = (dp[i][1][0] + dp[i - 1][0][0] + dp[i - 1][0][1] + dp[i - 1][0][2]) % mod
 
        ans = 0
        for j in range(2):
            for k in range(3):
                ans = (ans + dp[n - 1][j][k]) % mod
 
        return ans
 

The other languages (Java, C++, Go) follow a very similar structure, maintaining the 3D dp array and implementing the same recurrence relations. The key differences are primarily in syntax and data type handling. The core logic remains identical for optimal efficiency.