列表

详情


902. 最大为 N 的数字组合

给定一个按 非递减顺序 排列的数字数组 digits 。你可以用任意次数 digits[i] 来写的数字。例如,如果 digits = ['1','3','5'],我们可以写数字,如 '13''551', 和 '1351315'

返回 可以生成的小于或等于给定整数 n 的正整数的个数 。

 

示例 1:

输入:digits = ["1","3","5","7"], n = 100
输出:20
解释:
可写出的 20 个数字是:
1, 3, 5, 7, 11, 13, 15, 17, 31, 33, 35, 37, 51, 53, 55, 57, 71, 73, 75, 77.

示例 2:

输入:digits = ["1","4","9"], n = 1000000000
输出:29523
解释:
我们可以写 3 个一位数字,9 个两位数字,27 个三位数字,
81 个四位数字,243 个五位数字,729 个六位数字,
2187 个七位数字,6561 个八位数字和 19683 个九位数字。
总共,可以使用D中的数字写出 29523 个整数。

示例 3:

输入:digits = ["7"], n = 8
输出:1

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int atMostNGivenDigitSet(vector<string>& digits, int n) { } };

python3 解法, 执行用时: 32 ms, 内存消耗: 15.1 MB, 提交时间: 2022-10-18 15:11:25

class Solution:
    def atMostNGivenDigitSet(self, digits: List[str], n: int) -> int:
        '''
        dp[i][0] 表示由 digits 构成且 n 的前 i 位的数字的个数,
        dp[i][1] 表示由 digits 构成且等于 n 的前 i 位的数字的个数,
        可知 dp[i][1] 的取值只能为 0 和 1。
        '''
        m = len(digits)
        s = str(n)
        k = len(s)
        dp = [[0, 0] for _ in range(k + 1)]
        dp[0][1] = 1
        for i in range(1, k + 1):
            for d in digits:
                if d == s[i - 1]:
                    dp[i][1] = dp[i - 1][1]
                elif d < s[i - 1]:
                    dp[i][0] += dp[i - 1][1]
                else:
                    break
            if i > 1:
                dp[i][0] += m + dp[i - 1][0] * m
        return sum(dp[k])

python3 解法, 执行用时: 44 ms, 内存消耗: 15.1 MB, 提交时间: 2022-10-18 15:08:04

class Solution:
    def atMostNGivenDigitSet(self, digits: List[str], n: int) -> int:
        s = str(n)
        @cache
        def f(i: int, is_limit: bool, is_num: bool) -> int:
            if i == len(s): return int(is_num)  # 如果填了数字,则为 1 种合法方案
            res = 0
            if not is_num:  # 前面不填数字,那么可以跳过当前数位,也不填数字
                # is_limit 改为 False,因为没有填数字,位数都比 n 要短,自然不会受到 n 的约束
                # is_num 仍然为 False,因为没有填任何数字
                res = f(i + 1, False, False)
            up = s[i] if is_limit else '9'  # 根据是否受到约束,决定可以填的数字的上限
            # 注意:对于一般的题目而言,如果此时 is_num 为 False,则必须从 1 开始枚举,由于本题 digits 没有 0,所以无需处理这种情况
            for d in digits:  # 枚举要填入的数字 d
                if d > up: break  # d 超过上限,由于 digits 是有序的,后面的 d 都会超过上限,故退出循环
                # is_limit:如果当前受到 n 的约束,且填的数字等于上限,那么后面仍然会受到 n 的约束
                # is_num 为 True,因为填了数字
                res += f(i + 1, is_limit and d == up, True)
            return res
        return f(0, True, False)

上一题