[算法专栏] 爬楼梯问题

  题目:

  一个台阶总共有n 级,如果一次可以跳1 级,也可以跳2 级,求总共有多少种跳法。

  备注:

  这个题目经常出现,包括Microsoft 等比较重视算法的公司都曾先后选用过个这道题作为面试题或者笔试题。

  问题分析:

  如果只有1 级台阶,那显然只有一种跳法;

  如果有2 级台阶,那就有两种跳的方法了:一种是分两次跳,每次跳1 级;另外一种就是一次跳2 级。

  当台阶数>2 级时,第一次跳的时候就有两种不同的选择:一种是 第一次只跳1 级,此时跳法数目等于后面剩下的n-1 级台阶的跳法数目,即为f(n-1);另外一种选择是第一次跳2 级,此时跳法数目等于后面剩下的n-2 级台阶的跳法数目,即为f(n-2)。 所以,n 级台阶时的不同跳法的总数 f(n) = f(n-1) + f(n-2)。

           /  1       (n=1)
  即:f(n) =  2         (n=2)
           \  f(n-1) + (f-2)   (n>2)

  其实,这就是Fibonacci 序列。算法复杂度为:(O(n))。 

  伪代码如下:

int Fibonacci1(unsigned int N)  

{  

    if(N<=2)  

        return N;  

    int fibtwo=2;  

    int fibone=1;  

    int fibN=0;  

    for(unsigned int i=3;i<=N;i++)  

    {  

        fibN=fibone+fibtwo;  

        fibone=fibtwo;  

        fibtwo=fibN;  

    }  

    return fibN;  

}  

  具体实现如下(6种实现):

  1 /**
  2  * 爬楼梯问题: 实质就是斐波那契数列.
  3  * 
  4  * @author X-knight
  5  *
  6  */
  7 public class ClimbTheStairs {
  8     int total;
  9 
 10     // 递归调用
 11     public int fib01(int n) {
 12         if (n == 1 || n == 2)
 13             total = n;
 14         else
 15             total = fib01(n - 2) + fib01(n - 1);
 16         return total;
 17     }
 18 
 19     // 三目运算符
 20     public int fib02(int n) {
 21         return (n == 1 || n == 2) ? n : fib02(n - 2) + fib02(n - 1);
 22     }
 23 
 24     // 备忘录法
 25     public int dfs(int n, int[] array) {
 26         if (array[n] != 0) {
 27             return array[n];
 28         } else {
 29             array[n] = dfs(n - 1, array) + dfs(n - 2, array);
 30             return array[n];
 31         }
 32     }
 33 
 34     public int fib03(int n) {
 35         if (n == 0) {
 36             return 1;
 37         }
 38         if (n == 1 || n == 2) {
 39             return n;
 40         } else {
 41             int[] array = new int[n + 1];
 42             array[1] = 1;
 43             array[2] = 2;
 44             return dfs(n, array);
 45         }
 46     }
 47 
 48     // 动态规划法 (利用数组来存储)
 49     public int fib04(int n) {
 50         if (n == 0)
 51             return 1;
 52         int[] array = new int[n + 1];
 53         array[0] = 1;
 54         array[1] = 1;
 55         for (int i = 2; i <= n; i++) {
 56             array[i] = array[i - 1] + array[i - 2];
 57         }
 58         return array[n];
 59     }
 60 
 61     // 状态压缩法(又称滚动数组、滑动窗口,用于优化动态规划法的空间复杂度)
 62     public int fib05(int n) {
 63         if (n == 1 || n == 0)
 64             return 1;
 65         n = n - 1;
 66         int result = 0;
 67         int zero = 1;
 68         int first = 1;
 69         while (n > 0) {
 70             result = zero + first;
 71             zero = first;
 72             first = result;
 73             n--;
 74         }
 75         return result;
 76     }
 77 
 78     // 斐波那契数列的通项公式
 79     public int fib06(int n) {
 80         if (n == 0)
 81             return 1;
 82         if (n == 1 || n == 2)
 83             return n;
 84         int result = (int) Math.floor(
 85                 1 / Math.sqrt(5) * (Math.pow((1 + Math.sqrt(5)) / 2, n + 1) - Math.pow((1 - Math.sqrt(5)) / 2, n + 1)));
 86         return result;
 87     }
 88 
 89     @Test
 90     public void testClimb() {
 91         int num01 = fib01(7);
 92         System.out.println(num01);
 93         int num02 = fib02(8);
 94         System.out.println(num02);
 95         int num03 = fib03(0);
 96         System.out.println(num03);
 97         int num04 = fib04(8);
 98         System.out.println(num04);
 99         int num05 = fib05(8);
100         System.out.println(num05);
101         int num06 = fib06(2);
102         System.out.println(num06);
103     }
104 }

 

posted @ 2018-06-13 19:32 勋爵 阅读(...) 评论(...) 编辑 收藏