• 007 斐波那契数列


      原本以为比较简单,但是后来发现,加能使用动态规划,算法更好。

    1.题目

      大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。n<=39。

    2.分析递归方法

    1  public int fib0(int n)
    2     {
    3         if(n<=0)
    4             return 0;
    5         if(n==1)
    6             return 1;
    7         return fib( n-1)+fib(n-2);
    8     }

     假设输入的是6:

     

      

      上面的递归树中的每一个子节点都会执行一次,很多重复的节点被执行,fib(2)被重复执行了5次。由于调用每一个函数的时候都要保留上下文,所以空间上开销也不小。这么多的子节点被重复执行,如果在执行的时候把执行过的子节点保存起来,后面要用到的时候直接查表调用的话可以节约大量的时间。下面就看看动态规划的两种方法怎样来解决斐波拉契数列Fibonacci 数列问题。

    3.使用动态规划

      ①自顶向下的备忘录法

     1 public static int Fibonacci(int n)
     2     {
     3         if(n<=0)
     4             return n;
     5         int [] Memo=new int[n+1];
     6         for(int i=0;i<=n;i++)
     7             Memo[i]=-1;
     8         return fib(n, Memo);
     9     }
    10     public static int fib(int n,int []Memo)
    11     {
    12         if(Memo[n]!=-1)
    13             return Memo[n];
    14         //如果已经求出了fib(n)的值直接返回,否则将求出的值保存在Memo备忘录中。
    15         if(n<=2)
    16             Memo[n]=1;
    17         else Memo[n]=fib( n-1,Memo)+fib(n-2,Memo);
    18         return Memo[n];
    19     }

      备忘录法也是比较好理解的,创建了一个n+1大小的数组来保存求出的斐波拉契数列中的每一个值,在递归的时候如果发现前面fib(n)的值计算出来了就不再计算,如果未计算出来,则计算出来后保存在Memo数组中,下次在调用fib(n)的时候就不会重新递归了。比如上面的递归树中在计算fib(6)的时候先计算fib(5),调用fib(5)算出了fib(4)后,fib(6)再调用fib(4)就不会在递归fib(4)的子树了,因为fib(4)的值已经保存在Memo[4]中。

      ②自底向上的动态规划

      备忘录法还是利用了递归,上面算法不管怎样,计算fib(6)的时候最后还是要计算出fib(1),fib(2),fib(3)……,那么何不先计算出fib(1),fib(2),fib(3)……,呢?这也就是动态规划的核心,先计算子问题,再由子问题计算父问题。

     1 public static int fib(int n)
     2     {
     3         if(n<=0)
     4             return n;
     5         int []Memo=new int[n+1];
     6         Memo[0]=0;
     7         Memo[1]=1;
     8         for(int i=2;i<=n;i++)
     9         {
    10             Memo[i]=Memo[i-1]+Memo[i-2];
    11         }
    12         return Memo[n];
    13     }

      ③优化

      自底向上方法也是利用数组保存了先计算的值,为后面的调用服务。观察参与循环的只有 i,i-1 , i-2三项,因此该方法的空间可以进一步的压缩如下。

     1 public static int fib3(int n)
     2     {
     3         if(n<=1)
     4             return n;
     5 
     6         int Memo_i_2=0;
     7         int Memo_i_1=1;
     8         int Memo_i=1;
     9         for(int i=2;i<=n;i++)
    10         {
    11             Memo_i=Memo_i_2+Memo_i_1;
    12             Memo_i_2=Memo_i_1;
    13             Memo_i_1=Memo_i;
    14         }
    15         return Memo_i;
    16     }

    4.完整的程序

     1 package first;
     2 
     3 public class Fibonacci {
     4     public static void main(String[] args){
     5         //
     6         int a=Fibonacci(3);
     7         System.out.println("a="+a);
     8         //
     9         int b=fib(3);
    10         System.out.println("b="+b);
    11     }
    12 
    13     public int fib0(int n)
    14     {
    15         if(n<=0)
    16             return 0;
    17         if(n==1)
    18             return 1;
    19         return fib( n-1)+fib(n-2);
    20     }
    21 
    22 
    23     public static int Fibonacci(int n)
    24     {
    25         if(n<=0)
    26             return n;
    27         int [] Memo=new int[n+1];
    28         for(int i=0;i<=n;i++)
    29             Memo[i]=-1;
    30         return fib(n, Memo);
    31     }
    32     public static int fib(int n,int []Memo)
    33     {
    34         if(Memo[n]!=-1)
    35             return Memo[n];
    36         //如果已经求出了fib(n)的值直接返回,否则将求出的值保存在Memo备忘录中。
    37         if(n<=2)
    38             Memo[n]=1;
    39         else Memo[n]=fib( n-1,Memo)+fib(n-2,Memo);
    40         return Memo[n];
    41     }
    42 
    43     public static int fib(int n)
    44     {
    45         if(n<=0)
    46             return n;
    47         int []Memo=new int[n+1];
    48         Memo[0]=0;
    49         Memo[1]=1;
    50         for(int i=2;i<=n;i++)
    51         {
    52             Memo[i]=Memo[i-1]+Memo[i-2];
    53         }
    54         return Memo[n];
    55     }
    56 
    57     public static int fib3(int n)
    58     {
    59         if(n<=1)
    60             return n;
    61 
    62         int Memo_i_2=0;
    63         int Memo_i_1=1;
    64         int Memo_i=1;
    65         for(int i=2;i<=n;i++)
    66         {
    67             Memo_i=Memo_i_2+Memo_i_1;
    68             Memo_i_2=Memo_i_1;
    69             Memo_i_1=Memo_i;
    70         }
    71         return Memo_i;
    72     }
    73 
    74 
    75 
    76 }

     

  • 相关阅读:
    redis入门
    elementui入门
    1387:搭配购买(buy)
    P1536 村村通
    1388:家谱(gen)
    1389:亲戚
    1385:团伙(group)
    P1305 新二叉树
    P5076 【深基16.例7】普通二叉树(简化版)
    二叉搜索树(BST)模版
  • 原文地址:https://www.cnblogs.com/juncaoit/p/10416931.html
Copyright © 2020-2023  润新知