因此,对于Project Euler中的问题25,我必须找到Fibonacci序列中第一个数字的位置,数字为千位。
-- Lazily generates an infinite Fibonacci series
fib :: [Int]
fib = 1 : 1 : zipWith (+) fib (tail fib)
-- Checks if given number has a thousand digits.
checkDigits :: Int -> Bool
checkDigits number = length (show number) == 1000
-- Checks if position in Fibonacci series has a thousand digits.
checkFibDigits :: Int -> Bool
checkFibDigits pos = checkDigits (fib !! (pos - 1))
p25 = head (filter (\x -> checkFibDigits x == True) ([1..]))
出于某种原因,这种方法似乎无限期地挂起。如果我用10替换1000,它会吐出45,这是第一个数字的位置,有10位数。
要么我的方法效率低下,要么哈斯克尔用大数字做一些奇怪的事情。 Python中的类似方法非常完美。
感谢您的帮助!
答案 0 :(得分:3)
只需将Int
改为Integer
fib
和checkDigits
,您就会发现答案会立即出现:
fib :: [Integer]
fib = 1 : 1 : zipWith (+) fib (tail fib)
checkDigits :: Integer -> Bool
checkDigits number = length (show number) == 1000
这是因为Int
的大小有限,而Integer
具有受系统内存限制的任意精度。
答案 1 :(得分:3)
您的直接问题是在Int
类型中使用Integer
而不是fib
,这会将值限制为永远不会超过2 31 ,但除此之外,是的,你这样做的方式是非常低效的。也就是说,当它真的应该是O(n)时,它是O(n 2 )。你生成Fibonacci序列的方式很好,但是当你试图找到千位数的第一个值时,你会去:
基本上,您每次都会重新遍历链表。一种不同的方法可能是将索引和相应的Fibonacci结果压缩在一起:
ghci> take 10 $ zip [1..] fib
[(1,1),(2,1),(3,2),(4,3),(5,5),(6,8),(7,13),(8,21),(9,34),(10,55)]
然后你删除元素,直到Fibonacci值至少为1000位数,并取下第一个的索引:
ghci> fst $ head $ dropWhile ((< 1000) . length . show . snd) $ zip [1..] fib
4782