1. 程式人生 > >[算法專欄] 爬樓梯問題

[算法專欄] 爬樓梯問題

窗口 dfs rst 狀態壓縮 ID 問題分析 復雜 else !=

  題目:

  一個臺階總共有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 }

[算法專欄] 爬樓梯問題