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

LeetCode 902: Numbers At Most N Given Digit Set

·1 分鐘· ·
LeetCode Hard Dynamic-Programming Digit-Dp Math Binary-Search String
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

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

  • 提交紀錄:Accepted(一次通過)

解題思路
#

只能用給定的數字(沒有 0),數 <= n 的正整數。數位 DP,狀態 (pos, tight, started):

  • tight:前綴是否還貼著 n。貼著的時候,這一位只能選 <= n[pos] 的數字。
  • started:數字是否已經開始。還沒開始時可以跳過這一位,代表這個數的位數比 n 少;跳過之後一定比 n 小,所以 tight 變成 False。
  • 走完所有位數時,started 才算一個數(不算空的)。

我的解法
#

from functools import cache

class Solution:
    def atMostNGivenDigitSet(self, digits: List[str], n: int) -> int:
        s = str(n)

        @cache
        def dfs(i: int, tight: bool, started: bool) -> int:
            if i == len(s):
                return 1 if started else 0
            res = 0
            if not started:
                res += dfs(i + 1, False, False)    # 跳過這一位:位數更少的數
            for d in digits:                       # digits 已經排序
                if tight and d > s[i]:
                    break
                res += dfs(i + 1, tight and d == s[i], True)
            return res

        return dfs(0, True, False)

我 AC 的版本沒有在最後檢查 started,而是在倒數第一位之前才允許跳過(index != len - 1),一樣可以避免算到空的數字。

另一種做法是直接數:位數比 n 少的有 Σ |D|^k 個,位數一樣的逐位比較。

複雜度
#

時間 O(len(n) · |digits|),空間 O(len(n))。

要特別避免的錯誤
#

  • 跳過的那一位之後 tight 要變 False。
  • 不能把「全部都跳過」當成一個數。

面試口說整理
#

數位 DP,狀態是位置、是否貼著 n、是否已經開始。還沒開始時可以跳過這一位,代表位數比較少的數,這時一定比 n 小;開始之後每一位從給定的數字裡選,貼著 n 時不能超過 n 的這一位。走完時已經開始才算一個數。時間 O(len(n) · |digits|)。

相關文章

LeetCode 1147: Longest Chunked Palindrome Decomposition
·1 分鐘
LeetCode Hard Dynamic-Programming Greedy Two-Pointers Rolling-Hash String
LeetCode 1147 解題筆記:從兩端同時往內累積字串,左右一相等就切成一對;越早切越好,剩下的中間(如果有)算一塊
LeetCode 488: Zuma Game
·2 分鐘
LeetCode Hard Dynamic-Programming Memoization Breadth-First-Search String Stack
LeetCode 488 解題筆記:board 最多 16 顆、hand 最多 5 顆,把 (board, hand) 整個當狀態做 DFS + 記憶化;只在「同色球前面」和「拆開兩顆同色球」兩種位置插入
LeetCode 1745: Palindrome Partitioning IV
·1 分鐘
LeetCode Hard Dynamic-Programming Interval-Dp String
LeetCode 1745 解題筆記:先用區間 DP 建好 is_pal[i][j],再枚舉兩個切點,三段都是回文就成立,O(n^2)
LeetCode 3906: Count Good Integers on a Grid Path
·2 分鐘
LeetCode Hard Dynamic-Programming Digit-Dp
LeetCode 3906 解題筆記:範圍到 9 × 10^15,不能逐一檢查;數位 DP 同時帶上下界兩個 tight,路徑上的格子要非遞減,狀態多記「路徑上前一個數字」
LeetCode 1092: Shortest Common Supersequence
·4 分鐘
LeetCode Hard Dynamic-Programming String
LeetCode 1092 解題筆記,依照原始 learning note 重新整理
LeetCode 1312: Minimum Insertion Steps to Make a String Palindrome
·3 分鐘
LeetCode Hard Dynamic-Programming String Palindrome
LeetCode 1312 解題筆記,依照原始 learning note 重新整理