Leetcode 3490. Count Beautiful Numbers

  • [Leetcode 3490. Count Beautiful Numbers](#Leetcode 3490. Count Beautiful Numbers)
    • [1. 解题思路](#1. 解题思路)
    • [2. 代码实现](#2. 代码实现)

1. 解题思路

这道题能够自力搞定还是蛮开心的。

这道题主体的思路其实很清晰,就是将题目变换一下,变成写作一个count(n)函数来求取不大于数字 n n n的全部beautiful number的数目,这样,原始问题的答案就变成了count(r) - count(l-1)。因此,我们只需要考察这个count函数的实现即可,不过到这里其实也没怎么简化问题也就是了。

问题的关键在于这里这个beautiful number的定义,他是说其各个位上所有数的积能够被其各个位上的所有数的和整除。而题目中限制 n ≤ 1 0 9 n \leq 10^9 n≤109,因此事实上最大的数也就是 999999999 999999999 999999999,各个位上的digit的和最大也就是 81 81 81,因此,我们就可以变换命题为:

  • 求出所有不大于 n n n,且其各个位上的数字之和等于 k k k,且其积能够被 k k k整除的数的个数。

遍历 k k k从 1 1 1到 81 81 81,即可求出不大于 n n n的所有beautiful number的个数。

因此,命题最终也就变成了:

  • 求出所有不大于 n n n,且其各个位上的数字之和等于 k k k,且其积能够被 k k k整除的数的个数。

对于这个问题,我们就可以将其转换为一个动态规划的问题了,就是考察其每一个位上的数据的取值,然后考察其和以及积的变化即可。唯一需要注意的是:

  • 开头的0不能被计算到乘积当中,否则其就总是可以被 k k k整除了;
  • 需要考察当前位上的数的取值能否超过 n n n上的同一位置的数,即,如果两者之前的数均相同,那么当前位上的数取值不能超过 n n n上的同一位置的数。

2. 代码实现

给出最终的python代码实现如下:

python 复制代码
class Solution:
    def beautifulNumbers(self, l: int, r: int) -> int:
        
        def count_beatiful_numbers(num):
            if num <= 10:
                return num
            
            num_str = str(num)
            n = len(num_str)
            
            @lru_cache(None)
            def dp(idx, _sum, _prod, allow_larger, is_all_leading_zeros):
                if idx >= n:
                    return 1 if _sum == 0 and _prod == 1 else 0
                elif _sum == 0:
                    return 1
                elif 9 * (n-idx) < _sum:
                    return 0
                
                if allow_larger:
                    ans = 0
                    if is_all_leading_zeros:
                        ans += dp(idx+1, _sum, _prod, allow_larger, True)
                        for i in range(1, min(10, _sum+1)):
                            ans += dp(idx+1, _sum-i, _prod // gcd(_prod, i), True, False)
                    else:
                        for i in range(min(10, _sum+1)):
                            ans += dp(idx+1, _sum-i, _prod // gcd(_prod, i), True, False)
                else:
                    digit = int(num_str[idx])
                    ans = 0
                    if is_all_leading_zeros:
                        if digit == 0:
                            ans += dp(idx+1, _sum, _prod, False, True)
                        else:
                            ans += dp(idx+1, _sum, _prod, True, True)
                        for i in range(1, min(digit, _sum+1)):
                            ans += dp(idx+1, _sum-i, _prod // gcd(_prod, i), True, False)
                        if digit != 0 and digit <= _sum:
                            ans += dp(idx+1, _sum-digit, _prod // gcd(_prod, digit), False, False)
                    else:
                        for i in range(min(digit, _sum+1)):
                            ans += dp(idx+1, _sum-i, _prod // gcd(_prod, i), True, False)
                        if digit <= _sum:
                            ans += dp(idx+1, _sum-digit, _prod // gcd(_prod, digit), False, False)
                return ans
            
            ans = 0
            for i in range(1, 82):
                ans += dp(0, i, i, False, True)
            return ans
        
        return count_beatiful_numbers(r) - count_beatiful_numbers(l-1)

提交代码评测得到:耗时637ms,占用内存64.6MB。

相关推荐
橘颂TA16 小时前
【剑斩OFFER】算法的暴力美学——只出现一次的数字 ||
算法·leetcode·动态规划
草莓熊Lotso2 天前
《算法闯关指南:动态规划算法--斐波拉契数列模型》--01.第N个泰波拉契数,02.三步问题
开发语言·c++·经验分享·笔记·其他·算法·动态规划
稚辉君.MCA_P8_Java3 天前
Gemini永久会员 Java动态规划
java·数据结构·leetcode·排序算法·动态规划
少许极端3 天前
算法奇妙屋(十四)-简单多状态dp问题
算法·动态规划·图解算法·简单多状态dp·打家劫舍问题·买卖股票问题全解
稚辉君.MCA_P8_Java3 天前
Gemini永久会员 Go 实现动态规划
数据结构·后端·算法·golang·动态规划
利刃大大3 天前
【动态规划:背包问题】完全平方数
c++·算法·动态规划·背包问题·完全背包
醉颜凉4 天前
环形房屋如何 “安全劫舍”?动态规划解题逻辑与技巧
c语言·算法·动态规划
mjhcsp4 天前
C++ 动态规划(Dynamic Programming)详解:从理论到实战
c++·动态规划·1024程序员节
大雨淅淅4 天前
一文搞懂动态规划:从入门到精通
算法·动态规划
司铭鸿5 天前
化学式解析的算法之美:从原子计数到栈的巧妙运用
linux·运维·服务器·算法·动态规划·代理模式·哈希算法