LC 2719. 统计整数数目
还没有接触过这种数位 dp 的算法,我看了一下 讲解,大致思路就是:
- 将上限数字转变成为字符串
- 从第 0 个数字开始匹配
- 如果处于受限状态,那么就最多只能到对应数字上,否则就可以到 9
- 主要是针对字符串上的每个位置进行枚举
下面是题主给出的模板
- i 表示枚举的位置,从开头进行枚举
- sum 表示当前所有累计的数字之和
- isNum 表示当前是否得到的是有效数字,因为起始我么允许使用"000" 这样的,所有 isNum 开始就是 true. 这个里面可以省略
- isLimit 表示前缀是否被锁定
class Solution:
def count(self, num1: str, num2: str, min_sum: int, max_sum: int) -> int:
def doCount(num):
s = str(num)
from functools import cache
@cache
def f(i, sum, isNum, isLimit):
if sum > max_sum:
return 0
if i == len(s):
return sum >= min_sum and isNum
res = 0
down = 0 if isNum else 1
up = int(s[i]) if isLimit else 9
for d in range(down, up + 1):
res += f(i + 1, sum + d, True, isLimit and d == up)
return res
return f(0, 0, True, True)
a = doCount(num2)
b = doCount(num1)
c = (min_sum <= sum(map(int, num1)) <= max_sum)
ans = (a - b) + c
return ans
题主还给了这个题作为学习 https://leetcode.cn/problems/numbers-with-repeated-digits/
这题里面就需要维护一个 mask. 然后这题里面起始不允许出现前缀 0 这样的答案,所以一开始 isNum = false
class Solution:
def numDupDigitsAtMostN(self, n: int) -> int:
s = str(n)
from functools import cache
@cache
def f(i, mask, isNum, isLimit):
if i == len(s):
return isNum
res = 0
if not isNum:
res += f(i + 1, mask, False, False)
down = 0 if isNum else 1
up = int(s[i]) if isLimit else 9
for d in range(down, up + 1):
if not (mask & (1 << d)):
res += f(i + 1, mask | (1 << d), True, isLimit and d == up)
return res
a = f(0, 0, False, True)
ans = n - a
return ans