假设你正在爬楼梯。须要 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)