题解采用了数位动态规划的思想。首先,计算所有长度小于给定数字的特殊整数个数,然后计算长度等于给定数字的部分特殊整数。具体地,对于长度小于n的数,可以直接计算每个长度的特殊数字数量,例如长度为i的数字,其首位有9种选择(1-9),其余位从剩下的9个数字中选(i-1)个数字排列。对于长度等于n的情况,从最高位到最低位逐位确定数字,并排除已经使用过的数字,使用排列计算剩余位的可能组合。如果在某一位发现重复使用数字,则剩余部分不再构成特殊整数。
时间复杂度: O(n)
空间复杂度: O(n)
from math import perm
class Solution:
def countSpecialNumbers(self, num: int) -> int:
num = str(num) # 将数字转换为字符串,便于逐位处理
n = len(num) # 计算数字的长度
# 计算所有长度小于n的特殊数的总数
res = sum(9 * perm(9, i-1) for i in range(1, n))
s = set() # 用于记录已经使用过的数字
for i, c in enumerate(num): # 逐位检查数字
for j in range(0, int(c)):
if i+j==0 or j in s:
continue # 跳过已经使用过的数字
res += perm(10-i-1, n-i-1) # 计算剩余位的可能组合
if int(c) in s:
return res # 如果发生重复,返回当前计算结果
s.add(int(c)) # 将当前数字添加到已使用集合中
return res+1 # 包括数字本身在内的总数