LeetCode - 数位 DP

See 数位 DP 通用模板,附题单(Python/Java/C++/Go).

233. Number of Digit One

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def countDigitOne(self, n: int) -> int:
s = str(n)
@cache
def f(i: int, cnt1: int, is_limit: bool) -> int:
if i == len(s):
return cnt1
res = 0
up = int(s[i]) if is_limit else 9
for d in range(up + 1):
res += f(i + 1, cnt1 + (d == 1), is_limit and d == up)
return res
return f(0, 0, True)

2719. Count of Integers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
def count(self, num1: str, num2: str, min_sum: int, max_sum: int) -> int:
n = len(num2)
num1 = num1.zfill(n)

@cache
def dfs(i: int, s: int, limit_low: bool, limit_high: bool) -> int:
if s > max_sum:
return 0
if i == n:
return s >= min_sum

lo = int(num1[i]) if limit_low else 0
hi = int(num2[i]) if limit_high else 9
res = 0
for d in range(lo, hi + 1):
res += dfs(i + 1, s + d, limit_low and d == lo, limit_high and d == hi)
return res

return dfs(0, 0, True, True) % 1_000_000_007

788. Rotated Digits

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DIFFS = (0, 0, 1, -1, -1, 1, 1, -1, 0, 1)
class Solution:
def rotatedDigits(self, n: int) -> int:
s = str(n)
@cache
def f(i: int, has_diff: bool, is_limit: bool) -> int:
if i == len(s):
return has_diff
res = 0
up = int(s[i]) if is_limit else 9
for d in range(0, up + 1):
if DIFFS[d] != -1:
res += f(i + 1, has_diff or DIFFS[d], is_limit and d == up)
return res
return f(0, False, True)

902. Numbers At Most N Given Digit Set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution:
def atMostNGivenDigitSet(self, digits: List[str], n: int) -> int:
s = str(n)
@cache
def f(i: int, is_limit: bool, is_num: bool) -> int:
if i == len(s):
return int(is_num)
res = 0
if not is_num:
res = f(i + 1, False, False)
# no need coz digits[i] != 0
# low = 0 if is_num else 1
up = s[i] if is_limit else '9'
for d in digits:
if d > up:
break
res += f(i + 1, is_limit and d == up, True)
return res
return f(0, True, False)

2376. Count Special Integers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution:
def countSpecialNumbers(self, n: int) -> int:
s = str(n)
@cache
def f(i: int, mask: int, is_limit: bool, is_num: bool) -> int:
if i == len(s):
return int(is_num)
res = 0
if not is_num:
res = f(i + 1, mask, False, False)
low = 0 if is_num else 1
up = int(s[i]) if is_limit else 9
for d in range(low, up + 1):
if (mask >> d & 1) == 0:
res += f(i + 1, mask | (1 << d), is_limit and d == up, True)
return res
return f(0, 0, True, False)

600. Non-negative Integers without Consecutive Ones

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def findIntegers(self, n: int) -> int:
s = str(bin(n))[2:]
@cache
def f(i: int, pre1: bool, is_limit: bool) -> int:
if i == len(s):
return 1
up = int(s[i]) if is_limit else 1
res = f(i + 1, False, is_limit and up == 0)
if not pre1 and up == 1:
res += f(i + 1, True, is_limit)
return res
return f(0, False, True)

1012. Numbers With Repeated Digits

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution:
def numDupDigitsAtMostN(self, n: int) -> int:
s = str(n)
@cache
def f(i: int, mask: int, is_limit: bool, is_num: bool) -> int:
if i == len(s):
return int(is_num)
res = 0
if not is_num:
res = f(i + 1, mask, False, False)
low = 0 if is_num else 1
up = int(s[i]) if is_limit else 9
for d in range(low, up + 1):
if (mask >> d & 1) == 0:
res += f(i + 1, mask | (1 << d), is_limit and d == up, True)
return res
return n - f(0, 0, True, False)

357. Count Numbers with Unique Digits

1

3007. Maximum Number That Sum of the Prices Is Less Than or Equal to K

1

2827. Number of Beautiful Integers in the Range

1

2999. Count the Number of Powerful Integers

1

2801. Count Stepping Numbers in Range

1