项目欧拉:解决问题#5的一个(更好的)方法?

时间:2011-08-06 16:14:32

标签: haskell

你可能知道项目欧拉问题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和过滤器吗?

只是澄清一下,这不是家庭作业。我这样做是为了将我的大脑包裹在Haskell周围。 (到目前为止我输了!)

:Thanx all

我认为这是一种更为理智的方式(可能还有更多方法,但这就足够了)

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

4 个答案:

答案 0 :(得分:12)

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

euler = foldl lcm 2 [3..20]

这瞬间给了我232792560。

答案 1 :(得分:6)

由于扰流板已经发布,我想我会解释它是如何工作的。

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

λ> lcm 10 12
60

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

  

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

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

λ> foldl1 lcm [1..20]
232792560

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

答案 2 :(得分:3)

是的,你可以做得更好。首先,重写为

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

但是你真正需要的不是Haskell,而是一种更聪明的算法。提示:使用算术的基本定理。然后,您的Haskell解决方案将从标准的Eratosthenes筛子开始。

答案 3 :(得分:0)

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

我简化了一点:

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

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