我正在参与Euler Q3项目并需要获得一个数字的最大素数因子。到目前为止,我已经得到了一对函数来返回给定数字的所有因子的列表,但这似乎是一个非常糟糕的方法(部分因为我只需要最大的)。
get_factors :: (Integral a) => a -> [a] -> [a]
get_factors _ [] = []
get_factors t (x:xs)
| t `mod` x == 0 = x:get_factors t xs
| otherwise = get_factors t xs
factors :: (Integral a) => a -> [a]
factors x = get_factors x [x,x-1..1]
> factors 1000
> [1000,500,250,200,125,100,50,40,25,20,10,8,5,4,2,1]
对我来说,如果你要启动递归功能,我需要有一个“启动”功能似乎很奇怪(或者有一个函数,我必须将它传递两次相同的值,再次,对我来说似乎很愚蠢)。
你能指出我应该如何做到这一点的正确方向吗?
答案 0 :(得分:8)
您应该尝试认识到您在此处所做的事情,即从列表中选择满足某些条件的元素,这是一种非常常见的模式。此模式由Prelude中的filter
函数实现。
使用filter
,您可以将您的函数编写为:
factors n = filter (\d -> n `mod` d == 0) [n, n-1 .. 1]
或者,等效地,您可以使用列表理解:
factors n = [d | d <- [n, n-1 .. 1], n `mod` d == 0]
答案 1 :(得分:4)
使用“启动”函数调用递归函数在Haskell中很常见,所以不要害怕。通常它被写成
f = g someArgument
where
g = ...
在你的情况下
factors :: (Integral a) => a -> [a]
factors x = get_factors [x,x-1..1]
where
get_factors [] = []
get_factors (y:ys)
| x `mod` y == 0 = y : get_factors ys
| otherwise = get_factors ys
这表示您的代码的读者get_factors
仅在此使用,而在其他任何地方使用,并帮助您保持代码清洁。 get_factors
也可以访问x
,这样可以简化设计。
其他一些想法:
x
的素数的一部分并尝试除以它们。x
之间的所有素数。但如果x
是复合的,则其中一个因素必须是<= sqrt(n)
。您可以使用它来构建一个明显更好的算法。答案 2 :(得分:2)
我不认为通过像[n,n-1 ..]这样的每个数字是个好主意,因为问题是600851475143.
largest_factors :: Integer -> Integer
largest_factors n = helper n 2
where
helper m p
| m < p^2 = m
| m == p = m
| m `mod` p == 0 = helper (m `div` p) p
| otherwise = helper m (p+1)
我所做的是,一旦发现某个数字(比如p)除以数字n,它就会将它除以。这个在我的电脑上正常工作。这给了我一秒钟内的解决方案。