繁体   English   中英

在 Haskell 中有效地找到除数的数量

[英]Efficiently finding the number of divisors in Haskell

尝试在 Haskell 中解决 Project Euler 上的问题 12。

三角形数的序列是通过将自然数相加而产生的。

所以第 7 个三角形数将是 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28。前十项将是:

 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

让我们列出前七个三角形数的因数:

 1: 1 3: 1,3 6: 1,2,3,6 10: 1,2,5,10 15: 1,3,5,15 21: 1,3,7,21 28: 1,2,4,7,14,28 We can see that 28 is the first triangle number to have over five divisors.

第一个有超过 500 个除数的三角形数的值是多少?

我的解决方案适用于少量除数(例如,给定 5,它返回 28),但是当输入 500 时,它似乎无限期挂起。

-- Lazily generates infinite list of triangle numbers.
triangleNumbers :: [Integer]
triangleNumbers = map (\x -> sum [1..x]) [1..]

-- Given a number, returns the a tuple of how many divisors it has and the number.
numDivisors :: Integer -> (Int, Integer)
numDivisors num = (length [x | x <- [1..num], num `mod` x == 0], num)

p12 :: Integer
p12 = snd $ head $ filter (\x -> fst x > 500) $ map numDivisors triangleNumbers

你知道我可能做错了什么吗? 谢谢!

另一个问题是您生成的三角形数虽然正确,但效率非常低。 例如,要计算第 11 个数字求和 [1..11],然后计算第 12 个数字求和 [1..12],它不使用先前计算的结果。

正如我在评论中提到的,您可以直接使用n*(n+1)/2计算第 n 个三角形数。 但是,即使您不知道这个公式,您也可以通过使用这样的递归来利用连续三角形数之间的相似性:

triangulars = go 1 2
  where go s n = s : go (s+n) (n+1)

这种递归也被scanl函数捕获:

triangulars = scanl (+) 1 [2..]

问题是查找除数的函数非常慢,因为它测试所有数字。 还有更高效的功能。 例如,参见 StackOverflow 上这个问题的答案: 两个简单的代码来生成一个数的除数。 为什么递归的更快? .

但是如果你稍微谷歌一下,你会发现许多其他算法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM