Leetcode 509 斐波那契数 (图解)

暴力递归

/*
    斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。给出n求F(n).
*/
​
// 严格来讲,并不是一个正宗的动态规划问题,但是可以帮助我们理解动态规划的特性。
    
// 这题可以显示出一个动态规划问题的优化解题步骤:
​
/*暴力递归(自顶向下递,自下向上归) ----> 带备忘录的递归(自顶向下递,自下向上归)
                    
                    
*/
​
// 先看暴力递归
class Solution{
    public int fib(int n){
        // base case
        if(n == 0 || n == 1)return n ;
        // 递推关系
        return fib(n-1)+fib(n-2);
    }
}
// 递归的时间复杂度:递归函数的调用次数*递归函数本身的复杂度。
这题中递归函数本身就是两行代码,并没有任何的循环,所以时间复杂度是o(1),递归函数的调用次数大概是2^n,所以时间复杂度是o(2^n),二者相乘最终是o(2^n)

带备忘录的递归解法

将是一个树状结构转化为链表结构,将树的遍历计算转化为链表的遍历计算,速度大大提升。

// 在递归开始之前,先去备忘录查一下,看是否已经计算过了,如果已经计算过,就不再计算了。
class solution{
    
    // 外层调用该方法,计算递归数据。
    public int fib(int N){
        // 备忘录全初始化为0,因为索引从0开始,而该数组存储的是斐波那契数,所以要+1.在动态规划中,无论是二维数组还是一维数组都是很常见。
        int[] memo = new int[N + 1];
        // 进行带备忘录的递归
        return helper(memo,N);
    }
    
    private int helper(int[] memo,int n){
        // base case
        if(n == 0 || n == 1)return n;
        // 已经计算的,不需要再计算了,剪枝操作
        if(memo[n] != 0)return memo[n];
        memo[n] = helper(memo,n - 1) + helper(memo,n - 2);
        return memo[n];
    }
}
// 这回算法时间复杂度变为o(n),但空间复杂度变为o(n)

 dp 数组的迭代解法

class solution{
    public int fib(int N){
        if(N == 0)return 0;
        // dp 数组里面的内容和memo是完全一样的,只不过把递归改成了for循环迭代而已。
        int[] dp = new int[N + 1];
        // base case
        dp[0] = 0;
        dp[1] = 1;
        // 状态转移
        for(int i = 2;i <= N;i++)
           dp[i] = dp[i - 1] + dp[i - 2];
        
        return dp[N];
    }
}


// 进一步优化,可以不利用数组,将空间复杂度降为o(1)
class solution{
    public int fib(int n){
        // base case
        if(n == 0 || n == 1)return n;
        
        // 递推关系
        int prev = 0,curr = 1;
        for(int i = 2;i <= n;i++){
            int sum = prev + curr;
            prev = curr;
            curr = sum;
        }
        return curr;
    }
}

最后这种算法,才是真正的符合人的思维,递归这种思想想象起执行流程简直反人类,如果谁让我计算斐波那契数列的第5项,我能第一时间想到的解法就是,从后往前加就行了。而不是递到最后一层,再归到脸上来,太反人类了。

图片来自B站labuladong ,这人讲算法有一套,还出了一本算法书大家可看一看。

大家可以复制代码,去idea中debug一下,那样会对这个思想的体会更加深刻。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值