↓快轉到主要內容
  1. LeetCode/

LeetCode 552: Student Attendance Record II

·2 分鐘· ·
LeetCode Hard Dynamic-Programming State-Machine
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: hard 第一次嘗試:2026-07-08

  • 提交紀錄:Accepted ×3(同一天用三種寫法)

解題思路
#

合法的條件只跟兩件事有關:A 總共出現幾次(只能 0 或 1)、結尾連續幾個 L(只能 0、1、2)。所以狀態是 (a, l),共 6 種,dp[a][l] = 目前長度、處於這個狀態的紀錄數。

每天選一個字元:

  • P:A 不變,L 歸零 → (a, 0)。
  • A:只能從 a = 0 來,L 歸零 → (1, 0)。
  • L:A 不變,l + 1,只能從 l < 2 來 → (a, l + 1)。

初始只有 (0, 0) 是 1,跑 n 天後把 6 個狀態加起來。

我的解法
#

class Solution:
    def checkRecord(self, n: int) -> int:
        MOD = 10 ** 9 + 7
        dp = [[0] * 3 for _ in range(2)]           # dp[a][l]
        dp[0][0] = 1
        for _ in range(n):
            ndp = [[0] * 3 for _ in range(2)]
            for a in range(2):
                for l in range(3):
                    cur = dp[a][l]
                    if not cur:
                        continue
                    ndp[a][0] = (ndp[a][0] + cur) % MOD            # P
                    if a == 0:
                        ndp[1][0] = (ndp[1][0] + cur) % MOD        # A
                    if l < 2:
                        ndp[a][l + 1] = (ndp[a][l + 1] + cur) % MOD   # L
            dp = ndp
        return sum(map(sum, dp)) % MOD

我第一個 AC 的版本把 6 個狀態寫成 6 個變數,直接列出每個狀態從哪裡來(例如 (0, 0) 來自 (0, 0)、(0, 1)、(0, 2) 選 P),比較快(475ms vs 2 秒多);上面這種「每個狀態往外推」的寫法比較不容易漏掉轉移。

複雜度
#

時間 O(6n),空間 O(1)。(還可以用矩陣快速冪做到 O(log n)。)

要特別避免的錯誤
#

  • 選 A 時 L 要歸零,因為 A 打斷了連續的 L。
  • 每一輪要用新的 ndp,不能直接改 dp。

面試口說整理
#

合法與否只看兩件事:A 出現幾次、結尾連續幾個 L,所以狀態是 2 × 3 = 6 種。每天選 P 會讓 L 歸零,選 A 只能在還沒用過 A 時選,也讓 L 歸零,選 L 讓連續 L 加一但不能到 3。從初始狀態跑 n 天,最後把所有狀態加起來。時間 O(n)。

相關文章

LeetCode 1411: Number of Ways to Paint N × 3 Grid
·1 分鐘
LeetCode Hard Dynamic-Programming State-Machine Graph-Coloring
LeetCode 1411 解題筆記:一列的塗法只分兩種樣式:ABA(兩端同色)和 ABC(三色不同),各 6 種;下一列 ABA → 3 ABA + 2 ABC、ABC → 2 ABA + 2 ABC
LeetCode 123: Best Time to Buy and Sell Stock III
·3 分鐘
LeetCode Hard Dynamic-Programming State-Machine
LeetCode 123 解題筆記,依照原始 learning note 重新整理
LeetCode 188: Best Time to Buy and Sell Stock IV
·3 分鐘
LeetCode Hard Dynamic-Programming State-Machine
LeetCode 188 解題筆記,依照原始 learning note 重新整理
LeetCode 1402: Reducing Dishes
·1 分鐘
LeetCode Hard Dynamic-Programming Greedy Sorting Array
LeetCode 1402 解題筆記:排序後從滿意度大的開始選;每多選一道放在最前面,前面選的都往後一格,總和增加「目前選的滿意度總和」,總和是正的就繼續選
LeetCode 1526: Minimum Number of Increments on Subarrays to Form a Target Array
·1 分鐘
LeetCode Hard Dynamic-Programming Greedy Monotonic-Stack Array
LeetCode 1526 解題筆記:從左往右看,每次比前一個高,多出來的高度都要新開那麼多次操作;變矮的部分可以沿用之前的操作
LeetCode 1147: Longest Chunked Palindrome Decomposition
·1 分鐘
LeetCode Hard Dynamic-Programming Greedy Two-Pointers Rolling-Hash String
LeetCode 1147 解題筆記:從兩端同時往內累積字串,左右一相等就切成一對;越早切越好,剩下的中間(如果有)算一塊