求斐波那契数

斐波那契数列以如下被以递推的方法定义:

F(0)=0,F(1)=1,  F(n) = F(n - 1) + F(n - 2)(≥ 2,∈ N*)

普通递归版本会有大量重复计算,即递归树中有大量重复结点:

int fibonacci(int i) {
       if(i <= 0) return 0;
       if(i == 1) return 1;
       return fibonacci(i-1) + fibonacci(i-2);
}

一棵深度(按根节点深度为1)为k的二叉树最多可以有 2^k - 1 个节点,所以该递归算法的时间复杂度位O(2^n)。

既然当n>2时斐波那契数只取决于该数之前的两个数,那么只要我们将前两个数保存起来,求当前斐波那契数时只需进行一次加法运算而不需递归求前两个数了,这是用空间换时间的思路。

我们仍可以用递归的方法:

int Fibonacci1(int first, int second, int n)  //优化的递归算法,并非最优解,时间O(n),空间O(n)
{
    if(n <= 0) return 0;
    if(n == 1 || n == 2) return 1;
    if(n == 3) return first + second;
    return Fibonacci1(second, first + second, n - 1);
}

这种实现方式中 n 虽然是递减的,但 first 和 second 是从初值 1 开始累加的。调用时可以通过:

Fibonacci1(1, 1, n);

这种实现方式的递归树是单枝向下的,总共有O(n)个结点,每次递归有O(1)的操作,所以总的时间复杂度降为了O(n)。递归深度为O(n),每次递归占用常数级空间,故空间复杂度为O(n)。

按照此思路,我们可以写出该算法的非递归版本。我们用迭代法自底向上计算斐波那契数,还是需要用两个变量来存储斐波那契数列中相邻的前两个数:

int Fibonacci2(int n)  //非递归,时间O(n),空间O(1)
{
    if(n <= 0) return 0;
    if(n == 1 || n == 2) return 1;
    int first = 1, second = 1;
    int res;
    for(int i = 3; i <= n; i++){
        res = first + second;
        first = second;
        second = res;
    }
    return res;
}

迭代与上一版递归的差别在于,递归时自顶向下调用,自底向上求解,而迭代省去了自顶向下调用的过程,直接自底向上求解。没有了递归栈,迭代版本只用常数级空间,空间复杂度为O(1)。只需线性求解,时间复杂度为O(n)。

根据斐波那契数的性质,还有一种矩阵快速幂方法,待更新。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值