【问题标题】:Finding the largest power of a number that divides a factorial in haskell在haskell中找到除以阶乘的数字的最大幂
【发布时间】:2017-08-09 07:09:26
【问题描述】:

所以我正在编写一个 haskell 程序来计算除以阶乘的数字的最大幂。

largestPower :: Int -> Int -> Int

这里largestPower a b 找到了b 除以a! 的最大幂。

现在我明白了它背后的数学原理,找到答案的方法是将a(只是一个)除以b,忽略余数,最后将所有商相加。所以如果我们有类似的东西

largestPower 10 2

我们应该得到 8,因为 10/2=5/2=2/2=1,我们加上 5+2+1=8

但是,我无法弄清楚如何将它作为一个函数来实现,我是使用数组还是只是一个简单的递归函数。

我倾向于它只是一个普通函数,尽管我猜它可以通过将商存储在数组中并添加它们来完成。

【问题讨论】:

  • 是的,一个简单的递归函数就可以了。虽然你也可以根据需要使用列表。
  • @Bergi 你能给我一些关于这个功能的提示吗,我无法弄清楚。
  • 如果我没看错,不需要递归,一个简单的循环就足够了:(伪代码):divide = a;功率=0; while (dividend >= b) { 股息=round(dividend/b);power+=1;}
  • 递归是实现这一点的惯用方式。尝试更正式地写出你对数学的理解。
  • 您不必添加 5+2+1。你简单算一下有三个分区,然后计算2^3 = 8。这个总和有效的事实只是巧合。

标签: algorithm haskell recursion functional-programming


【解决方案1】:

没有累加器的递归

您可以简单地编写一个递归算法并总结每次调用的结果。这里我们有两种情况:

  • a小于b,此时最大幂为0。所以:

    largestPower a b | a < b = 0
    
  • a 大于或等于b,在这种情况下,我们将a 除以b,计算该除法的largestPower,并将除法添加到结果中。喜欢:

                     | otherwise = d + largestPower d b
                     where d = (div a b)
    

或者把它放在一起:

largestPower a b | a < b = 1
                 | otherwise = d + largestPower d b
                 where d = (div a b)

累加器的递归

您还可以将 recursionaccumulator 一起使用:您通过递归传递的变量,并相应地更新。最后,您返回该累加器(或在该累加器上调用的函数)。

这里的累加器当然是部门的运行产品,所以:

largestPower = largestPower' <b>0</b>

所以我们将定义一个函数largestPower'(注意口音),其第一个参数是累加器,初始化为1

现在在递归中,有两种情况:

  • a小于b,我们直接返回累加器:

    largestPower' r a b | a < b = r
    
  • 否则我们将累加器与b 相乘,然后通过递归调用将除法传递给largestPower'

                        | otherwise = largestPower' (d+r) d b
                        where d = (div a b)
    

或完整版:

largestPower = largestPower' 1

largestPower' r a b | a < b = r
                    | otherwise = largestPower' (d+r) d b
                    where d = (div a b)

朴素正确的算法

算法不正确。一个“幼稚”的算法是简单地划分每个项目并不断递减,直到达到1,例如:

largestPower 1 _ = 0
largestPower a b = sumPower a + largestPower (a-1) b
    where sumPower n | n `mod` b == 0 = 1 + sumPower (div n b)
                     | otherwise = 0

所以这意味着对于largestPower 4 2,可以写成:

largestPower 4 2 = sumPower 4 + sumPower 3 + sumPower 2

和:

sumPower 4 = 1 + sumPower 2
           = 1 + 1 + sumPower 1
           = 1 + 1 + 0
           = 2

sumPower 3 = 0

sumPower 2 = 1 + sumPower 1
           = 1 + 0
           = 1

所以3

【讨论】:

  • 这里的算法正确吗?我觉得应该是(div a b) + largestPower (div a b) b
  • @Lazersmoke:假设您计算largestPower 2 3。这应该是1,而不是2...问题中指定的添加只是一个不正确的算法。
  • @Lazersmoke:请参阅添加到答案中的注释。
  • @WillemVanOnsem 我试过这段代码,如果最大功率 10 5,它给出了错误的答案,它应该是 2,但它给出了 5 作为答案
  • @sgman:不知何故,我跳过了阶乘部分。将更新答案。
【解决方案2】:

上述算法可以很简单地实现:

largestPower :: Int -> Int -> Int
largestPower 0 b = 0
largestPower a b = d + largestPower d b where d = a `div` b

但是,该算法不适用于复合 b。例如,largestPower 10 6 使用此算法得到1,但实际上正确答案是4。问题是该算法忽略了不是6 的倍数的23 的倍数。不过,如何修复算法是一个完全独立的问题。

【讨论】:

  • 在我看来正确答案是4
  • @WillemVanOnsem 你完全正确。修好了,谢谢。这就是我匆忙做数学得到的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-27
  • 2016-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多