Algorithm 丑陋的数字—;DP方法

Algorithm 丑陋的数字—;DP方法,algorithm,dynamic-programming,Algorithm,Dynamic Programming,问题: 丑陋的数字是唯一的素数因子为2、3或5的数字。序列1、2、3、4、5、6、8、9、10、12、15……显示了前11个丑陋的数字。按照惯例,包括1个 给定一个数字n,任务是查找第n个丑陋的数字。 () 答案:上述链接中的动态规划方法 伪代码: 1 Declare an array for ugly numbers: ugly[n] 2 Initialize first ugly no: ugly[0] = 1 3 Initialize three array index variabl

问题: 丑陋的数字是唯一的素数因子为2、3或5的数字。序列1、2、3、4、5、6、8、9、10、12、15……显示了前11个丑陋的数字。按照惯例,包括1个

给定一个数字
n
,任务是查找第n个
丑陋的数字。
()

答案:上述链接中的动态规划方法

伪代码:

1 Declare an array for ugly numbers:  ugly[n]
2 Initialize first ugly no:  ugly[0] = 1
3 Initialize three array index variables i2, i3, i5 to point to 
   1st element of the ugly array: 
        i2 = i3 = i5 =0; 
4 Initialize 3 choices for the next ugly no:
         next_mulitple_of_2 = ugly[i2]*2;
         next_mulitple_of_3 = ugly[i3]*3
         next_mulitple_of_5 = ugly[i5]*5;
5 Now go in a loop to fill all ugly numbers till 150:
For (i = 1; i < 150; i++ ) 
{
    /* These small steps are not optimized for good 
      readability. Will optimize them in C program */
    next_ugly_no  = Min(next_mulitple_of_2,
                        next_mulitple_of_3,
                        next_mulitple_of_5); 

    ugly[i] =  next_ugly_no       

    if (next_ugly_no  == next_mulitple_of_2) 
    {             
        i2 = i2 + 1;        
        next_mulitple_of_2 = ugly[i2]*2;
    } 
    if (next_ugly_no  == next_mulitple_of_3) 
    {             
        i3 = i3 + 1;        
        next_mulitple_of_3 = ugly[i3]*3;
     }            
     if (next_ugly_no  == next_mulitple_of_5)
     {    
        i5 = i5 + 1;        
        next_mulitple_of_5 = ugly[i5]*5;
     } 

}/* end of for loop */ 
6.return next_ugly_no
1为丑陋的数字声明数组:丑陋[n]
2初始化第一个丑陋编号:丑陋[0]=1
3初始化三个数组索引变量i2、i3、i5以指向
丑陋数组的第一个元素:
i2=i3=i5=0;
4为下一个丑陋的否初始化3个选项:
下一个2=丑陋的[i2]*2;
下一个三分之一=丑陋[i3]*3
下一个5中的多个=丑陋[i5]*5;
5现在循环填充所有丑陋的数字,直到150:
对于(i=1;i<150;i++)
{
/*这些小步骤不是为了好的目的而优化的
可读性。将在C程序中优化它们*/
next\u丑陋\u否=最小值(next\u MULTIPLE\u/2,
下一步是第三步中的第三步,
下一个(第5个中的多个);
下一个
如果(下一个丑陋的否==下一个2的多个)
{             
i2=i2+1;
下一个2=丑陋的[i2]*2;
} 
如果(下一个丑陋的否==下一个3的多个)
{             
i3=i3+1;
下一个_mulitple_of_3=丑陋[i3]*3;
}            
如果(下一个丑陋的否==下一个5的多个)
{    
i5=i5+1;
下一个5中的多个=丑陋[i5]*5;
} 
}/*循环结束*/
6.返回下一个\u丑陋\u编号
怀疑:

我不理解这种情况下的DP方法

  • 子问题是什么
  • 这种情况下的递归是什么
  • 子问题如何重叠
  • 为什么我们要跟踪当前的丑陋数字?为什么不直接通过2,3,5的倍数,每个点都保持最小值呢

    比如2,3,5。然后4,3,5,然后4,6,5..不断增加每个的倍数

  • 相关问题:(我浏览了答案,但我对上面提到的问题感到困惑。)

  • 子问题:查找所有2、3、5的倍数
  • 递归:使用以前的丑陋数字来计算未来的丑陋数字。动态规划解决方案通过使用存储缩短了递归的需要
  • 重叠:输出需要按数字顺序,因此不清楚哪个子问题将按顺序生成下一个子问题
  • 为什么要跟踪:如果不重复使用以前的丑陋数字,你只能得到指数结果2^n、3^n、5^n

  • 进一步优化:通过修剪丑陋的数组来取消设置这就是我如何根据子问题来描述问题的方式:

    第i个丑陋数字是将另一个丑陋数字(严格小于第i个)乘以2、3或5得到的。第一个难看的数字是1

    因此:

    // dp[i] ... the i-th ugly number
    dp[1] = 1;
    i2 = i3 = i5 = 1;
    for i in 2 .. n:
      dp[i] = min(2*dp[i2], 3*dp[i3], 5*dp[i5]);
      // where: 1 <= i2, i3, i5 < i
    
      i2 = update(dp[i], i2, 2);
      i3 = update(dp[i], i3, 3);
      i5 = update(dp[i], i5, 5);
    return dp[n];
    
    以下是拟议算法的运行方式:

    子问题确实重叠。以
    dp[6]
    dp[4]
    为例。两者都是通过使用dp[2]
    生成的,分别乘以3和2

    为了建立丑陋数字的索引,必须使用自底向上的方法(参考本节下的“自底向上方法”项目符号)构建解决方案。在计算
    dp[i]
    时,您可以将
    dp[i2]
    dp[i3]
    dp[i5]
    看作是记忆的递归调用

    Geeksforgeks实施说明
    • 不要进行堆分配;太慢了

      • 最好的方法是分配
        dp
        数组一次(确保它是 足够大)并在所有测试用例中重复使用它
    • 不要使用子程序;太慢了

      • min(min(a,b,c)
        可以,
        min({a,b,c})
        (c++)将超过时间限制

      • update()
        必须将逻辑集成到主算法中

    • 输入大(10k线);考虑使用某种缓冲区 阅读工具


    确实有一个更简单但更慢的(
    O(n log n)
    )解决方案,您已经暗示过了,并且在的答案中指出了这一点。这是Java中的外观:

    TreeSet multiples=新树集();
    长优先=1;
    对于(int i=1;i
    注 这样的解决方案不太可能超过Geeksforgeks设定的时限

    给定
    t
    测试用例,每个测试用例由要计算的丑陋数字的序号(
    n
    )指定,我们可以表示两种解决方案的时间复杂性:

    • t*n
      -用于线性解决方案

    • t*n*log2(n)
      -用于“
      TreeSet
      ”解决方案

    将二者相除会使“
    TreeSet
    ”解决方案的速度降低多少倍 相对于线性的:

    t * n * log2(n)
    --------------- = log2(n)
    t * n
    
    线性解决方案的运行时间约为600至800毫秒;平均700人

    如果我们将其乘以
    log2(10000)
    .7s*log2(10000)=6.98s
    ),我们将得到“
    TreeSet
    ”解决方案的运行时近似值,它远远高于设定的时间限制:

    预期时限<1.2736秒

    t=int(输入())
    #函数以获取给定范围内具有素数因子的所有数字
    def基本(n):
    全局l
    a=[]
    i=1
    
    while(我想你需要把那篇文章中的问题贴在这里。当链接失效时,整个问题和答案对每个人来说都是无用的。@Rob包括在内,谢谢你的建议。我
    t * n * log2(n)
    --------------- = log2(n)
    t * n
    
    t = int(input())
    
    # function to get all the numbers with prime factors within a given range
    
    def prime(n):
        global l
        a = []
        i = 1
        while (i <= n):
            k = 0
            if (n % i == 0):
                j = 1
                while (j <= i):
                    if (i % j == 0):
                        k = k + 1
                    j = j + 1
                if (k == 2):
                    a.append(i)
            i = i + 1
        check(a)
    
    #function to filter all non-ugly numbers
    
    def check(a):
        if (all(x in l for x in a)):
            everything.append(n)
    
    # main code
    
    while t >0:
        h = int(input())
        l = [2, 3, 5]
        everything = []
        for n in range(1, h**2):
            prime(n)
        print(everything[h - 1])
        t-=1