假設你正在爬樓梯。須要 n 階你才能到達樓頂。
每次你能夠爬 1 或 2 個臺階。你有多少種不一樣的方法能夠爬到樓頂呢?
注意:給定 n 是一個正整數。
示例 1:javascript
輸入: 2 輸出: 2 解釋: 有兩種方法能夠爬到樓頂。 1. 1 階 + 1 階 2. 2 階
示例 2:java
輸入: 3 輸出: 3 解釋: 有三種方法能夠爬到樓頂。 1. 1 階 + 1 階 + 1 階 2. 1 階 + 2 階 3. 2 階 + 1 階
每次能夠爬 1 或 2 個臺階。當咱們爬 4 個臺階時,就是爬 3 個臺階的方法數,加上爬 2 個臺階的方法數,等於 F(3) + F(2) = 3 + 2 = 5。因此當咱們爬 N 個臺階,就有 F(N - 1) + F(N - 2) 種方法。數組
咱們能夠用遞歸的方法獲得全部小於N的方法數,並把它們相加得出結果。遞歸結束的標誌爲 N=1 或 N =2。優化
var climbStairs = function(n) { if (n == 1) return 1 if (n == 2) return 2 return climbStairs(n - 1) + climbStairs(n - 2) };
時間複雜度 O($2^n$)。這種暴力解題的方法會超出時間限制,顯然不是咱們想要的。code
從上一種方法咱們能夠發現,每一步的結果都作了上一步的重複計算。好比F(6) + F(5) 後會計算 F(5) + F(4),F(5) 咱們已經計算過了,就不要重複計算了。因此咱們能夠用一個數組來儲存計算結果,方便重複利用。遞歸
var climbStairs = function(n) { let arr = [] function climb(n) { if (n == 1) return 1 if (n == 2) return 2 if (arr[n] > 0) return arr[n] arr[n] = climb(n - 1) + climb(n - 2) return arr[n] } return climb(n) };
時間複雜度 O(n),優化以後提升了速度,已經不會超出時間限制了。ip
和遞歸的思路同樣,把一個大問題分解成多個小問題,只是此次咱們使用循環的方式,減小內存的開銷。內存
var climbStairs = function(n) { if (n == 1) return 1 if (n == 2) return 2 let arr = [] arr[1] = 1 arr[2] = 2 for (let i = 3; i<= n; i++) { arr[i] = arr[i - 1] + arr[i - 2] } return arr[n] };
時間複雜度 O(n),優化了內存的消耗,速度沒有提高。io
從上一個方案咱們能夠看出這是一個斐波那契數列。function
var climbStairs = function(n) { if (n == 1) return 1 if (n == 2) return 2 let first = 1 let second = 2 for (let i = 3; i<= n; i++) { let third = first + second first = second second = third } return second };
時間複雜度 O(n)