你可能知道项目欧拉问题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)
答案 0 :(得分:12)
在这种特殊情况下,您可以使用foldl
和lcm
免费获取:
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,因此必须是我们的数字。这减少了你的例子中的一些混乱。请注意,此方法非常慢;你能想出一个更好的数学方法来解决这个问题吗?开始考虑主要因素...