【问题标题】:Project Euler: A (much) better way to solve problem #5?欧拉计划:解决问题 5 的(更好)方法?
【发布时间】:2015-01-23 04:21:52
【问题描述】:

你可能知道欧拉项目第 5 题:求能被 1 到 20 整除的最小数。

我应用的逻辑是“从大于列表中最大值的第一个数字(20)开始,并且可以被它整除,即 40”,步长为 20(最大数字)

我使用列表推导来做到这一点,但它很蹩脚。

pe5 = head    [x|x<-[40,60..],x`mod`3==0,x`mod`4==0,x`mod`6==0,x`mod`7==0,x`mod`8==0,x`mod`9==0,x`mod`11==0,x`mod`12==0,x`mod`13==0,x`mod`14==0,x`mod`15==0,x`mod`16==0,x`mod`17==0,x`mod`18==0,x`mod`19==0] 

也许我们可以使用 zipWith 和 filter 做得更好吗?

澄清一下,这不是家庭作业。我这样做是为了让我的大脑围绕 Haskell。 (到目前为止我输了!)

:谢谢大家

我认为这是一种更明智的方法(可能还有数千种更好的方法,但这已经足够了)

listlcm'::(Integral a)=> [a] -> a
listlcm' [x] = x
listlcm' (x:xs) = lcm x (listlcm' xs)  

【问题讨论】:

  • 没有算法变化,只是一个更短的版本head [x | x &lt;- [40,60..], all (\y -&gt; x rem` y == 0) [1..20]]`
  • 如果你想要一个更好的算法,你可以考虑lcm
  • @is7s 我没有要求更好的算法,但感谢您提供的线索,一切都在“as”处理程序中?
  • 顺便说一句,这个问题的标题有点非描述性(“这个”部分可以再澄清一点)
  • @hvr thanx,从现在开始我会更精确

标签: haskell


【解决方案1】:

在这种特殊情况下,您可以使用foldllcm 免费获得它:

euler = foldl lcm 2 [3..20]

这立即给了我 232792560。

【讨论】:

  • foldl' 可能更好(至少,对于大输入:))
  • 甚至更短:foldl1 lcm [2..20]
【解决方案2】:

由于剧透已经发布,我想我应该解释一下它是如何工作的。

能被两个数整除的最小数也称为这些数的最小公倍数。 Prelude中有一个计算这个的函数。

λ> lcm 10 12
60

现在,为了将其扩展到多个数字,我们利用以下属性

lcm(a1, ... an) = lcm(lcm(a1, ... a n-1), an)

在 Haskell 中,f(f(... f(a1, a2), ...), an) 可以写成foldl1 f [a<sub>1</sub>, a<sub>2</sub>, ... a<sub>n</sub>],所以我们可以用这个简单的单行来解决问题:

λ> foldl1 lcm [1..20]
232792560

这会在几分之一秒内找到解决方案。

【讨论】:

  • 我知道这有点太容易了..我知道 foldl 的功能(列表左侧的连续函数组合)我认为我的 listlcm 更容易(对于新手)阅读我的编辑!
  • @Vasu:也许对于初学者来说,但是当一个标准的高阶函数可以完成这项工作时,编写自己的递归通常被认为是一种反模式。尽管在某些情况下这会降低代码的可读性,但这里并非如此。
【解决方案3】:

是的,你可以做得更好。对于初学者,重写为类似

head [x | x<-[40,60..], all (\y -> x`mod`y == 0) [2..20] ]

但你真正需要的不是更流畅的 Haskell,而是更智能的算法。提示:使用算术基本定理。然后,您的 Haskell 解决方案将从标准的埃拉托色尼筛示例开始。

【讨论】:

  • 在看到这个之前,我写过all (==0) $ zipWith mod (repeat x) [3..20],但我认为你的更简洁。
  • 另一个将运行时间减半的简单优化是将[2..20]更改为[11..19]
【解决方案4】:

由于这是一个学习 Haskell 的练习,我只会指出有一种更有效的方法可以在数学上解决这个问题,但我会让你自己弄清楚。相反,让我们使用您的逻辑在 Haskell 中解决问题。

我稍微简化了一下:

head [x | x <- [20,40..], length( filter ( \y -> x `mod` y /= 0) [1..20]) == 0]

这会在除数列表上创建一个过滤器,当它的长度为 0 时,这意味着所有除数都除以我们的 x,所以它必须是我们的数字。这减少了您在示例中的一些混乱。请注意,此方法非常慢;你能想出更好的数学方法来解决这个问题吗?开始研究质因数分解...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多