NC65:斐波那契数列/LeetCode:509.斐波那契数
斐波那契数列
https://www.nowcoder.com/practice/c6c7742f5ba7442aada113136ddea0c3?tpId=188&&tqId=38580&rp=1&ru=/activity/oj&qru=/ta/job-code-high-week/question-ranking
1、介绍
斐波那契数列(Fibonacci sequence),又称黄金分割数列或兔子数列,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……
标准公式为:
简单理解就是从第二项开始,当前值等于前两项之和
LC 509.斐波那契数:https://leetcode-cn.com/problems/fibonacci-number/
2、解法
(1)递归法
分析
根据标准公式为:采用递归进行细化拆分
先从上往下递归,然后再从下往上回溯,最后回溯的时候合并子树求得答案。
代码实现
public class Solution { public int Fibonacci(int n) { if(n == 0 || n == 1){ return n; } return Fibonacci(n-1) + Fibonacci(n-2); } }
优点:代码简单好写,缺点:慢,会超时
时间复杂度:
空间复杂度:
(2)动态规划(优化递归)
分析
- 通过上图会发现,方法一中使用递归会存在很多重复计算,因此为了改进,可以把使用数组将计算过的保存下来。
- 如果想让空间继续优化,那就用动态规划,优化掉递归栈空间,方法一是从上往下递归的然后再从下往上回溯的,在最后的回溯过程中来合并子树从而求得答案。
- 而使用动态规划,不用递归的过程,直接从子树求得答案,过程是从下往上。
代码实现1
public class Solution { public int Fibonacci(int n) { int ans[] = new int[40];//因为此题n≤39,所以直接设置数组大小为40 ans[0] = 0; ans[1] = 1; for(int i=2; i<=n; i++){//从第二项开始计算到第n项,用数组进行保存 ans[i] = ans[i-1] + ans[i-2]; } return ans[n]; } }
代码实现2
根据输入的n确定数组的大小,n小于等于1就直接确定数组的值,大于1就从第三项开始计算到第n项,用数组进行保存
class Solution { public int fib(int n) { int[] dp = new int[n+1]; if(n == 0){ dp[0] = 0; }else if(n == 1){ dp[0] = 0; dp[1] = 1; }else{ dp[0] = 0; dp[1] = 1; for(int i = 2; i <= n; i++){ dp[i] = dp[i - 1] + dp[i - 2]; } } return dp[n]; } }
时间复杂度:
空间复杂度:
(3)动态规划(优化存储)
分析
因为从第二项开始,当前值等于前两项之和,所以可以使用三个变量:
存储第n-2项的值,存储第n-1项的值,存储第n项的值,
代码实现
public class Solution { public int Fibonacci(int n) { if(n <= 0){ return 0; } if( n == 1){ return 1; } int n1 = 0; int n2 = 1; int n3 = 0; for(int i = 2; i <= n; i++){ n3 = n1 + n2; //根据前两项计算当前值 n1 = n2;//n1,n2继续表示下一项的值 n2 = n3; } return n3; } }
时间复杂度:
空间复杂度:
3、扩展
NC68:跳台阶/LC 70.爬楼梯
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
分析
根据题意得,跳台阶n从0开始的规律为0,1,2,3,5,8,13......与斐波那契数列类似,只是少了一个1
n3 = n1 + n2; n1 = n2; n2 = n3; //可使用两个参数实现优化 n2 = n1 + n2; //这里n2相当于获得了n3的值 n1 = n2 - n1; //n1获得了n2的值
实现代码
public class Solution { public int jumpFloor(int target) { if(target <= 0){ return 0; } if( target < 4){ //数列为0,1,2,3,5,8,13... return target; } int n1 = 2; int n2 = 3; for(int i = 4; i <= target; i++){//这里需要从第四项开始 n2 = n1 + n2; n1 = n2 - n1; } return n2; } }