本文最后更新于 170 天前,如有失效请评论区留言。
数位dp变通较大, 需要理解题意运用何种变量
eg.(变量名可以任取)
- i : 不必多言, dp核心
- limitHigh : 表示当前是否受到了 finish 的约束(我们要构造的数字不能超过 finish)。若为真,则第 i 位填入的数字至多为 finish[i],否则至多为 9,这个数记作 hi。如果在受到约束的情况下填了 finish[i],那么后续填入的数字仍会受到 finish 的约束。例如 finish=123,那么 i=0 填的是 1 的话,i=1 的这一位至多填 2。
- limitLow : 表示当前是否受到了 start 的约束(我们要构造的数字不能低于 start)。若为真,则第 i 位填入的数字至少为 start[i],否则至少为 0,这个数记作 lo。如果在受到约束的情况下填了 start[i],那么后续填入的数字仍会受到 start 的约束。
- mask : 表示前面选过的数字集合,换句话说,第 i 位要选的数字不能在 mask 中。(结合位运算)
- isNum : 表示 i 前面的数位是否填了数字。若为假,则当前位可以跳过(不填数字),或者要填入的数字至少为 1;若为真,则要填入的数字可以从 0 开始。例如 n=123,在 i=0 时跳过的话,相当于后面要构造的是一个 99 以内的数字了,如果 i=1 不跳过,那么相当于构造一个 10 到 99 的两位数,如果 i=1 跳过,相当于构造的是一个 9 以内的数字。
下面贴几个实例:
https://leetcode.cn/problems/count-special-integers/description/
class Solution:
def countSpecialNumbers(self, n: int) -> int:
low, high = str(1), str(n)
n = len(high)
low = "0" * (n - len(low)) + low
@cache
def dfs(i, mask, limit_low, limit_hi, isnum):
if i == n:
return int(isnum)
res = 0
if not isnum and low[i] == "0":
res += dfs(i + 1, mask, True, False, False)
lo = int(low[i]) if limit_low else 0
hi = int(high[i]) if limit_hi else 9
l0 = 0 if isnum else 1
for k in range(max(l0, lo), hi + 1):
if (mask >> k & 1) == 0:
res += dfs(i + 1, mask | (1 << k), limit_low and k == lo, limit_hi and k == hi, True)
return res
return dfs(0, 0, True, True, False)
https://leetcode.cn/problems/count-the-number-of-powerful-integers/description/
class Solution:
def numberOfPowerfulInt(self, start: int, finish: int, limit: int, s: str) -> int:
# 如果前导零对数位和无影响(sum+0=sum),模板中的 isNum 可以省略。
low, high = str(start), str(finish)
n = len(high)
low = ("0" * (n - len(low)) + low)
# 也可以low=low.zfill(n)表示,一般都是low数位长度小,为和high长度一样,在前面加前导零
pre = n - len(s)
@cache
def dfs(i, limit_low, limit_hi):
if i == n:
return 1
lo = int(low[i]) if limit_low else 0
hi = int(high[i]) if limit_hi else 9
res = 0
if i < pre:
for k in range(lo, min(hi, limit) + 1):
res += dfs(i + 1, limit_low and k == lo, limit_hi and k == hi)
else:
x = int(s[i - pre])
if lo <= x <= min(hi, limit):
res += dfs(i + 1, limit_low and x == lo, limit_hi and x == hi)
return res
return dfs(0, True, True)
https://leetcode.cn/problems/non-negative-integers-without-consecutive-ones/description/
class Solution:
def findIntegers(self, n: int) -> int:
@cache
def dfs(i: int, pre1: bool, is_limit: bool) -> int:
if i < 0:
return 1
up = n >> i & 1 if is_limit else 1
res = dfs(i - 1, False, is_limit and up == 0) # 填 0
if not pre1 and up == 1: # 可以填 1
res += dfs(i - 1, True, is_limit) # 填 1
return res
return dfs(n.bit_length() - 1, False, True) # 从高位到低位