导读:本期聚焦于小伙伴创作的《如何用数字动态规划高效计算指定范围内数字和小于等于X的整数数量》,敬请观看详情。在算法开发中,经常需要统计指定区间内满足数字和小于等于给定阈值X的整数数量,暴力遍历的方式时间复杂度极高,无法应对大范围数据场景。数字动态规划作为数位DP的典型应用,通过记忆化递归和状态定义,可以大幅降低计算复杂度,高效完成统计任务。本文将详细介绍数字动态规划的核心思路,拆解状态定义、转移逻辑和边界处理规则,同时给出完整的代码实现和示例验证,帮助开发者快速掌握这类问题的解决方法,应对实际开发中的相关计数需求。

数字动态规划是处理数位相关计数问题的常用方法,针对指定范围内数字和小于等于X的整数数量统计场景,它通过按位拆分数字、记录中间状态的方式,避免重复计算,大幅提升运行效率。

如何用数字动态规划高效计算指定范围内数字和小于等于X的整数数量

核心思路拆解

我们需要统计区间[L, R]内所有数字的数位和小于等于X的整数数量,通常可以转化为计算[0, R]的满足条件的数量减去[0, L-1]的满足条件的数量,因此核心是实现计算[0, N]范围内数位和小于等于X的整数数量的函数。

状态定义

定义递归函数dfs(pos, sum, limit, n),各参数含义如下:

  • pos:当前处理的数位位置,从最高位开始向下遍历
  • sum:当前已经累计的数位和
  • limit:布尔值,表示当前位是否受到N的数位限制,如果为true则当前位最大只能取N的对应位数值,否则可以取0-9
  • n:传入的上界数字N,用于获取每一位的数值

状态转移逻辑

递归到最低位(pos为-1)时,判断累计数位和sum是否小于等于X,是则返回1,否则返回0。对于每一位,先确定当前位可选取的最大数字:如果limit为true,最大为N的第pos位数值,否则为9。遍历0到该最大值,更新累计数位和和limit状态,递归计算下一位的结果并累加。

记忆化优化

为了避免重复计算,使用三维数组memo[pos][sum][limit]存储已经计算过的结果,其中limit需要转为0和1存储,因为布尔值在数组索引中无法直接作为维度。

完整代码实现

以下是Python语言的完整实现代码:

def count_valid_numbers(n, x):
    # 将数字转为字符串方便按位获取
    s = str(n)
    length = len(s)
    # 记忆化数组,limit用0和1表示
    memo = [[[-1 for _ in range(2)] for _ in range(x + 1)] for _ in range(length)]
    
    def dfs(pos, sum_val, limit):
        # 递归到最低位,判断数位和是否满足条件
        if pos == length:
            return 1 if sum_val <= x else 0
        # 如果已经计算过,直接返回结果
        if memo[pos][sum_val][1 if limit else 0] != -1:
            return memo[pos][sum_val][1 if limit else 0]
        # 确定当前位可选取的最大值
        max_digit = int(s[pos]) if limit else 9
        res = 0
        # 遍历当前位所有可能的数字
        for d in range(max_digit + 1):
            new_sum = sum_val + d
            # 如果新的数位和已经超过x,后续不需要继续计算
            if new_sum > x:
                continue
            new_limit = limit and (d == max_digit)
            res += dfs(pos + 1, new_sum, new_limit)
        # 存储当前状态的结果
        memo[pos][sum_val][1 if limit else 0] = res
        return res
    
    return dfs(0, 0, True)

def count_range(l, r, x):
    # 计算[l, r]范围内满足条件的数量
    if l == 0:
        return count_valid_numbers(r, x)
    return count_valid_numbers(r, x) - count_valid_numbers(l - 1, x)

# 示例验证
l = 10
r = 50
x = 5
result = count_range(l, r, x)
print(f"区间[{l}, {r}]内数位和小于等于{x}的整数数量为:{result}")

示例说明

以区间[10, 50]、X=5为例,符合条件的数字有10(1+0=1)、11(1+1=2)、12(1+2=3)、13(1+3=4)、14(1+4=5)、20(2+0=2)、21(2+1=3)、22(2+2=4)、23(2+3=5)、30(3+0=3)、31(3+1=4)、32(3+2=5)、40(4+0=4)、41(4+1=5),共14个,运行上述代码可以得到相同结果。

注意事项

  • 数位和的阈值X不能设置过大,否则记忆化数组的sum维度会过大,可根据实际场景调整
  • 处理左边界为0的场景时,不需要额外减1,避免负数出现
  • 如果数字范围超过64位整数,可以先将数字转为字符串再按位处理,避免数值溢出

数字动态规划数位DP数字和计算范围计数修改时间:2026-06-13 08:09:12

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。