6396. 统计整数数目

2023/06/04 leetcode 共 1178 字,约 4 分钟

title

problem link

给你两个数字字符串 num1 和 num2 ,以及两个整数 max_sum 和 min_sum 。如果一个整数 x 满足以下条件,我们称它是一个好整数:

  • num1 <= x <= num2
  • min_sum <= digit_sum(x) <= max_sum.

请你返回好整数的数目。答案可能很大,请返回答案对 109 + 7 取余后的结果。

注意,digit_sum(x) 表示 x 各位数字之和。

示例 1:

输入:num1 = "1", num2 = "12", min_num = 1, max_num = 8
输出:11
解释:总共有 11 个整数的数位和在 1 到 8 之间,分别是 1,2,3,4,5,6,7,8,10,11 和 12 。所以我们返回 11 。

示例 2:

输入:num1 = "1", num2 = "5", min_num = 1, max_num = 5
输出:5
解释:数位和在 1 到 5 之间的 5 个整数分别为 1,2,3,4 和 5 。所以我们返回 5 。

提示:

  • 1 <= num1 <= num2 <= 1022
  • 1 <= min_sum <= max_sum <= 400

solution

数位DP, 套用模板即可。is_num其实可省略,因为前导零对数位和无影响(数位和加上 0 不变)

class Solution:
    def count(self, num1: str, num2: str, min_sum: int, max_sum: int) -> int:
        MOD = int(1e9 + 7)
        import functools
        @functools.lru_cache(None)
        def f(i: int, leftsum: int, is_limit: bool, is_num: bool, s: str):
            if i == len(s):
                # print(leftsum)
                # 最后一位了,合法则return 1
                if leftsum >= min_sum:
                    return int(is_num)
                return 0
            res = 0
            if not is_num:
                # 此时已经有前缀0了,因此不受限
                res += f(i + 1, leftsum, False, False, s)
                res %= MOD
            # 数位i的上限
            up = int(s[i]) if is_limit else 9
            # 如果是is_num, 则可以从0开始,否则只能从1开始,毕竟是第一位数字
            for d in range(1 - int(is_num), up + 1):
                if d + leftsum > max_sum: break
                # 没用过该数字
                res += f(i + 1, leftsum + d, is_limit and d == up, True, s)
                res %= MOD
            return res % MOD

        b = f(0, 0, True, False, num2)
        b %= MOD
        # print(b)
        a = f(0, 0, True, False, str(int(num1) - 1))
        b %= MOD
        # print(a)
        return (b - a + MOD)%MOD

Search

    Table of Contents