我正在研究Project Euler问题14.这是我的解决方案。
import Data.List
collatzLength :: Int->Int
collatzLength 1 = 1
collatzLength n | odd n = 1 + collatzLength (3 * n + 1)
| even n = 1 + collatzLength (n `quot` 2)
maxTuple :: (Int, Int)->(Int, Int)->Ordering
maxTuple (x1, x2) (y1, y2) | x1 > y1 = GT
| x1 < y1 = LT
| otherwise = EQ
我正在运行以下GHCi
maximumBy maxTuple [(collatzLength x, x) | x <- [1..1000000]]
我知道如果严格评估Haskell,那么这个时间就像O(n 3 )。由于Haskell懒惰地评估,看起来这应该是n的一些常数倍。这已经运行了近一个小时了。似乎很不合理。有谁知道为什么?
答案 0 :(得分:22)
您假设collatzLength
函数将被记忆。 Haskell不进行自动记忆。你需要自己做。以下是使用data-memocombinators包的示例。
import Data.List
import Data.Ord
import qualified Data.MemoCombinators as Memo
collatzLength :: Integer -> Integer
collatzLength = Memo.arrayRange (1,1000000) collatzLength'
where
collatzLength' 1 = 1
collatzLength' n | odd n = 1 + collatzLength (3 * n + 1)
| even n = 1 + collatzLength (n `quot` 2)
main = print $ foldl1' max $ [(collatzLength n, n) | n <- [1..1000000]]
使用-O2
编译时,大约需要1秒钟。
答案 1 :(得分:1)
为了能够找到最大值的列表,需要对整个列表进行评估。
因此它会从collatzLength
到1
计算1000000
,collatzLength
是递归的。最糟糕的是,你对collatzLength
的定义甚至不是尾递归的。
答案 2 :(得分:0)
cL
是collatzLength
cL!!n
代表collatzLength n
cL :: [Int]
cL = 1 : 1 : [ 1 + (if odd n then cL!!(3*n+1) else cL!!(n `div` 2)) | n <- [2..]]
简单测试:
ghci> cL !! 13
10