这是我对这项任务的稍微不同的方法,它更有效。
提升的关键是不一直检查到最后,而只检查到它的平方根。我的意思是,如果我们想找到 100 的复合数,我们不需要控制所有 100 个数字。我们只需要控制到sqrt 100(如[2..10])就可以看到(mod 100 x) == 0。我们从 2 开始,因为您不想要 1 和数字本身。一旦我们得到满意的数字100 div x 应该给我们另一个。因此,如果 2 是复合数,那么 100 div 2 (50) 是另一个,例如 4 产生 25,5 产生 20。当然,当我们达到 10 时,它会给我们另外 10 个,我们只会评估其中一个。酷..!
这就是代码
kcomposites :: Int -> [Int]
kcomposites k =
let factors n = concat [bool [x, n `div` x] [x] (x^2 == n)
| x <- [2..limit], n `mod` x == 0]
where limit = truncate . sqrt . realToFrac $ n
in foldr (\n rs -> bool rs (n:rs) (k == (length . factors $ n))) [] [2..]
这是前 5 个元素在 k = 19 时代码的性能;
*Main> take 5 . kcomposites $ 19
[576,1600,2916,3136,7744]
(0.43 secs, 174,826,272 bytes)
这是您的代码在前 5 个元素的 k = 19 时的性能;
*Main> take 5 . kcomposite $ 19
[576,1600,2916,3136,7744]
(17.61 secs, 6,246,022,504 bytes)
注意:我不建议为 5 个元素检查 k = 5。即使是这段代码也花了大约 15 分钟才能得出[64,729,15625,117649,1771561] 上面的代码可能会花费大量时间(可能需要一天或更长时间)。
让我们将它们与take 3 进行比较。
*Main> take 3 . kcomposites $ 5
[64,729,15625]
(1.14 secs, 472,228,880 bytes)
*Main> take 3 . kcomposite $ 5
[64,729,15625]
(69.84 secs, 25,409,801,688 bytes)