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

LeetCode 2376: Count Special Integers

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

基本資料
#

難易度: hard 第一次嘗試:2026-09-05

  • 提交紀錄:Accepted ×2

解題思路
#

數 [1, n] 裡每一位都不重複的數。數位 DP,狀態 (pos, tight, started, mask):

  • mask:10 bit,記錄哪些數字已經用過。這一位不能選 mask 裡的數字。
  • started:前導零不算用過 0。還沒開始時放 0,mask 不變;第一個非 0 的數字出現之後才開始記。
  • 走完時 started 才算一個正整數。

我的解法
#

from functools import cache

class Solution:
    def countSpecialNumbers(self, n: int) -> int:
        s = str(n)

        @cache
        def dfs(i: int, tight: bool, started: bool, mask: int) -> int:
            if i == len(s):
                return 1 if started else 0
            hi = int(s[i]) if tight else 9
            count = 0
            for d in range(hi + 1):
                if mask >> d & 1:
                    continue                       # 這個數字用過了
                now_started = started or d != 0
                new_mask = mask | (1 << d) if now_started else mask   # 前導零不記
                count += dfs(i + 1, tight and d == hi, now_started, new_mask)
            return count

        return dfs(0, True, False, 0)

複雜度
#

狀態數最多 10 × 2 × 2 × 2^10,每個枚舉 10 個數字,大約 4 × 10^5。

要特別避免的錯誤
#

  • 前導零記成用過 0:像 10 這種數會被誤判。
  • mask 和 started 都要放進 cache 的 key。

面試口說整理
#

數位 DP,狀態是位置、是否貼著 n、是否已經開始、用過哪些數字的 mask。這一位不能選 mask 裡的數字;還沒開始時放 0 不記進 mask,因為前導零不是真的數字。走完時已經開始才算。狀態數是 10 × 4 × 1024,很小。

相關文章

LeetCode 902: Numbers At Most N Given Digit Set
·1 分鐘
LeetCode Hard Dynamic-Programming Digit-Dp Math Binary-Search String
LeetCode 902 解題筆記:數位 DP,狀態是 (pos, tight, started);還沒開始時可以跳過這一位,代表位數比 n 少的數
LeetCode 2912: Number of Ways to Reach Destination in the Grid
·2 分鐘
LeetCode Hard Dynamic-Programming State-Machine Math Combinatorics
LeetCode 2912 解題筆記:格子太多,但相對終點只分四類:終點、同一列、同一行、都不同;每一類的總方法數一起轉移,O(k)
LeetCode 3906: Count Good Integers on a Grid Path
·2 分鐘
LeetCode Hard Dynamic-Programming Digit-Dp
LeetCode 3906 解題筆記:範圍到 9 × 10^15,不能逐一檢查;數位 DP 同時帶上下界兩個 tight,路徑上的格子要非遞減,狀態多記「路徑上前一個數字」
LeetCode 2163: Minimum Difference in Sums After Removal of Elements
·2 分鐘
LeetCode Hard Dynamic-Programming Heap Array
LeetCode 2163 解題筆記:枚舉第一段和第二段的分界 k;左邊 nums[:k] 選 n 個最小的(最大堆維護),右邊 nums[k:] 選 n 個最大的(最小堆維護),前後綴各掃一次
LeetCode 2963: Count the Number of Good Partitions
·1 分鐘
LeetCode Hard Math Combinatorics Hash-Table Array
LeetCode 2963 解題筆記:同一個數的所有出現位置必須在同一段,用最後出現位置把陣列切成 b 個不可再分的區塊;區塊之間可切可不切,答案是 2^(b-1)
LeetCode 2328: Number of Increasing Paths in a Grid
·2 分鐘
LeetCode Hard Dynamic-Programming Grid-Dp Memoization Topological-Sort Matrix
LeetCode 2328 解題筆記:嚴格遞增所以沒有環;dp[cell] = 1 + Σ dp[比它大的鄰居],依值由大到小處理(或記憶化 DFS),全部加起來