【问题标题】:Haskell tail recursion for Fibonacci sequence斐波那契数列的 Haskell 尾递归
【发布时间】:2021-11-27 23:02:47
【问题描述】:

所以我正在做一个任务,我必须找到第 n 个斐波那契数,我遇到了下面显示的这个想法,但是这会返回一个列表,我只想返回最终数字,例如 fibo 3 会给我 [0,1,1,2,3,5,8,13],除了我只想返回 13,有什么办法可以做到吗?这是我第一次使用 Haskell,我也是第一次学习函数式编程,感谢任何帮助。谢谢

fibo :: Integral x => x -> [x]
fibo n = fiboHelper [0,1] 0 1 n
fiboHelper :: Integral x => [x]->x->x->x->[x]
fiboHelper l x y 0 = l
fiboHelper l x y n = fiboHelper (l ++ [y+x] ++ [y+x+y]) (x+y) (y+x+y) (n-1)

【问题讨论】:

  • 可能是fibo 7 = 13,而不是fibo 3

标签: haskell recursion


【解决方案1】:

是的,您可以跟踪递归堆栈的最后两个步骤。

fibo :: Integral x => x -> x
fibo a
  | a < 3      = 1
  | otherwise  = go 2 1 1 where
    go a' b' c'
       | a' == a    = c'
       | otherwise  = go (a'+1) (c') (b'+c')

附带说明一下,我学会了一种在 Haskell 中创建无限斐波那契数列的非常有趣的方法如下:

fibs = 1 : scanl (+) 1 fibs

将此与takelast 结合使用,您可以实现您正在寻找的任何解决方案。

take 5 fibs
-- produces [1,1,2,3,5]

last $ take 5 fibs
-- produces 5

【讨论】:

    【解决方案2】:

    您可以使用包含两个变量的辅助函数:第一项和第二项,以及每个

    fibo :: (Integral a, Integral b) => a -> b
    fibo 0 = 0
    fibo n = fiboHelper 0 1 (n-1)
    
    fiboHelper :: (Integral a, Integral b) => a -> a -> b -> a
    fiboHelper si si1 n
        | n <= 0 = si1
        | otherwise = fiboHelper si1 (si+si1) (n-1)
    

    这会产生:

    Prelude> fibo 7
    13
    

    至于您问题中的算法,通常在列表的右侧追加 不是 一个好主意,因为它以线性时间与左操作数的大小一起运行。因此,这意味着您的算法在 O(n2) 时间内运行。您可以将其实现为:

    fibo :: (Integral a, Integral b) => a -> [b]
    fibo 0 = [0]
    fibo n = 0 : fiboHelper 0 1 (n-1)
    
    fiboHelper :: (Integral a, Integral b) => a -> a -> b -> [a]
    fiboHelper si si1 n
      | n < 0 = []
      | otherwise = si1 : fiboHelper si1 (si+si1) (n-1)
    

    这将产生:

    Prelude> fibo 7
    [0,1,1,2,3,5,8,13]
    

    【讨论】:

      【解决方案3】:

      您只需要跟踪最后两个斐波那契数,而不是一个列表,这样您就可以将它们加在一起以进行下一次迭代。可以使用定义您想要的重复关系

      -- replace a and b with (a+b) and a, respectively, forgetting b.
      helper a b n == fiboHelper (a+b) a (n-1)
      helper a b 1 == a
      helper _ b 0 == b
      

      (第二种情况并非绝对必要,但避免了不必要的添加。)

      随着n 变小,所需值“累积”在第二个参数中,最终结果为n == 0 时的值。

      请注意,您可以通过为ab 提供不同的初始值来获得不同的系列。比如fibo = helper 1 0,而Lucas numbers是由lucas = helper 1 2定义的:

      lucas 5 = helper 1 2 5
              == helper 3 1 4
              == helper 4 3 3
              == helper 7 4 2
              == helper 11 7 1
      (       == helper 18 11 0)
              == 11
      

      【讨论】:

        猜你喜欢
        • 2014-04-02
        • 2011-07-27
        • 2012-07-24
        • 2012-11-19
        • 2016-11-07
        • 2012-02-16
        • 1970-01-01
        • 1970-01-01
        • 2010-12-03
        相关资源
        最近更新 更多