k-复合数是一个复合数,其中k个因子不包括1和它自身。我试图编写将采用整数k的代码并返回所有k-composite的无限列表。所以使用take 5 $ kcomposite 2将返回[6,8,10,14,15]。我写了两个函数来完成这个:
factors :: Int -> [Int]
factors n = [x | x <- [1..n], n `mod` x == 0]
kcomposite :: Int -> [Int]
kcomposite n = [x | x <- [1..], (length (factors n)) == (x-2)]
我编译没有问题,但是当我尝试运行它们时,ghci永远不会停止运行。这是有道理的,因为无限列表,但即使我只尝试获取列表中的前几个元素,就像在上面的例子中一样。我无法理解我做错了什么。
答案 0 :(得分:5)
k-复合数是一个复合数,其中k个因子不包括1和它本身
由于您的factors
函数会返回数字的所有因子(包括1
及其本身),因此该数字将大于提供的k
。这就是为什么您需要与k + 2
而不是k - 2
进行比较
此外,当k
小于0
时,您仍然会让程序永远不会停止运行,这就是您可能想要处理此边缘情况的原因。
factors :: Int -> [Int]
factors n = [x | x <- [1..n], n `mod` x == 0]
kcomposite :: Int -> [Int]
kcomposite k
| k < 0 = []
| otherwise = [x | x <- [1..], length (factors x) == (k + 2)]
答案 1 :(得分:2)
这是我对此任务略有不同的方法,效率更高。
提升键是不一直检查到最后但仅限于平方根。我的意思是,如果我们想找到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)