LeetCode:902. Numbers At Most N Given Digit Set - Python

问题描述:

902. 最大为 N 的数字组合

我们有一组排序的数字 D,它是 {'1','2','3','4','5','6','7','8','9'}的非空子集。(请注意,'0'不包括在内。)

现在,我们用这些数字进行组合写数字,想用多少次就用多少次。例如D = {'1','3','5'},我们可以写出像'13', '551', '1351315'这样的数字。

返回可以用D中的数字写出的小于或等于N的正整数的数目。

示例 :

输入:D = [“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.

提示:

  • D是按排序顺序的数字'1'-'9'的子集。
  • 1 <= N <= 10^9

问题分析:

(1)首先明确一个问题,就是给的数字集合 D 是不重复的,感觉这一点还是很重要的。
(2)假设数字 NK 位, 很显然,K-1 的数字一定比它小,那么能组成 K-1 位的数有多少那?答案为(K-1)^(len(D)),理解就是每一位有 len(D) 种选择,所以是它的次方个。
(3)由(2)可以求出位数为1 - (K-1) 位 的数的个数了,现在位数为 K,其比 N 小的数字怎么求?动态规划方法
(4)–求位数为K且小于 N 的数字个数–, 思路:
(5)从数据集D中依次拿出 一个数去和N的最高位比较,如果比它小,后面各个位上的数字可以任意组合,通过求次方就可以得到。
(6)如果比它小,很显然,后面再怎么组合也是不符合要求的,所以直接舍弃。
(7)如果相等,现在也很显然,竟然最高位相等,那么就可以直接等于次高位符合要求的个数(形成子问题 – 动态规划的一个必要条件)。然后把所有的累加,就是位数为 K 且小于N的数字个数。

dp状态方程如下:

设:dp[i:] 表示,从左向开始,第 i 个数字表示最高位时的,符合要求的数字个数。

for i in range(K-1, -1, -1):
    for d in D:
        if d < S[i]:
            dp[i] += len(D) ** (K-i-1)
        elif d == S[i]:
            dp[i] += dp[i+1]

Python3实现:

class Solution:
    def atMostNGivenDigitSet(self, D, N):

        S = str(N)
        K = len(S)
        dp = [0] * K + [1]  # 初始化dp

        for i in range(K-1, -1, -1):  # 开机计算dp[i]
            for d in D:
                if d < S[i]:  # 小于的情况
                    dp[i] += len(D) ** (K-i-1)
                elif d == S[i]:  # 相等的情况
                    dp[i] += dp[i+1]
        return dp[0] + sum(len(D) ** i for i in range(1, K))  # 最终结果


if __name__ == '__main__':
    D, N = ["1", "3", "5", "7"], 100
    solu = Solution()
    print(solu.atMostNGivenDigitSet(D, N))

声明: 总结学习,有问题可以批评指正,大神可以略过哦。

参考链接:leetcode.com/problems/numbers-at-most-n-given-digit-set/solution/

你可能感兴趣的:(算法,Python,LeetCode)