【发布时间】:2021-02-16 21:05:17
【问题描述】:
我正在学习更多关于动态编程的知识,并试图在 haskell 中实现它。我正在用不同的方法编写算法进行测试,发现一种比另一种更快。这是斐波那契问题
fib1 :: [Integer]
fib1 = 0:1:zipWith (+) fib1 (tail fib1)
fib2 :: [Integer]
fib2 = 0:1:[(fib2 !! (n-1)) + (fib2 !! (n-2)) | n <- [2..]]
fib1 比 fib2 快得多,但我不知道为什么。 fib2 看起来很直观,第 n 个数字是 (n-1)st 加上 (n-2)nd。 我得到了 fib1,但看起来它每次都在压缩整个列表,所以不会花费更长的时间。只是计算下一个索引?
【问题讨论】:
-
计算
fib2 !! n的成本随n线性增长。这是一个链表而不是向量。顺便说一句,最近关于斐波那契的问题有一些指示:SO_q66180076 -
我意识到 fib2 !由于链表,n 是线性的。但是fib1呢?那不也是链表吗?
-
@Ro-Bert 是的,但是每次
fib1被要求生成另一个数字时,它只需要做 O(1) 的工作,而不是像fib2这样的 O(n)。 (显然,加上Integer添加所需的时间,但这对于两种实现来说都是一样的。) -
好的。我想我有点预料到会发生这种情况。我知道 fib2 每次都有 O(n),所以它实际上是 O(n^2)。那么我不正确理解 zipWith 吗?我觉得这也应该是 O(n)。除非它不像 for 循环那样遍历列表。
-
其实这帮了大忙。我在想 zipWith 也是线性的。但这有助于我进行研究。我发现这个线程stackoverflow.com/questions/55291798/… 很好地解释了它。