假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
【解题思路】
一、递归方法
与青蛙跳台阶问题,其原理是完全一样的:
- 当n等于1的时候,只需要跳一次即可,只有一种跳法,记f(1)=1;
- 当n等于2的时候,可以先跳一级再跳一级,或者直接跳二级,共有2种跳法,记f(2)=2;
- 当n等于3的时候,他可以从一级台阶上跳两步上来,也可以从二级台阶上跳一步上来,所以总共有f(3)=f(2)+f(1);
同理当等于n的时候,总共有f(n)=f(n-1)+f(n-2)(这里n>2)种跳法。
所以如果我们求上到n阶有多少种,代码很简单,直接递归就行:
1 int climbStairs(int n){ 2 if( n == 1 ) 3 return 1; 4 if( n == 2 ) 5 return 1; 6 7 return climbStairs( n-1 ) + climbStairs( n-2 ); 8 }
但是,当n比较大的时候会超时。如果还想使用递归,可以改为尾递归的方式:
1 int Fibonacci(int n, int a, int b) 2 { 3 if (n <= 1) 4 return b; 5 return Fibonacci(n - 1, b, a + b); 6 } 7 8 int climbStairs(int n) 9 { 10 return Fibonacci( n, 1, 1 ); 11 }
二、非递归方法(动态规划)
爬第n阶楼梯的方法数量,等于以下两部分之和:
- 爬上 n-1 阶楼梯的方法数量。因为再爬1阶就能到第n阶;
- 爬上 n-2 阶楼梯的方法数量,因为再爬2阶就能到第n阶;
所以我们得到公式 dp[n] = dp[n-1] + dp[n-2];
同时需要初始化 dp[0]=1和 dp[1]=1;
1 int climbStairs(int n) 2 { 3 int *dp; 4 int i; 5 int val; 6 7 dp = (int *)malloc( sizeof(int) * (n + 1) ); 8 dp[0] = 1; 9 dp[1] = 1; 10 for( i = 2; i <= n; i++ ) 11 { 12 dp[i] = dp[i-1] + dp[i-2]; 13 } 14 val = dp[n]; 15 16 free(dp); 17 18 return val; 19 }
三、非递归方法优化(滚动数组)
我们看到上面的数组当前值是依赖他前面两个值的(前两个除外),我们只需要用两个临时变量即可,不需要申请一个数组;
int climbStairs(int n) { int i; int p = 0, q = 0, r = 1; for ( i = 1; i <= n; i++ ) { p = q; q = r; r = p + q; } return r; }
参考引用:
https://leetcode-cn.com/problems/climbing-stairs/solution/pa-lou-ti-by-leetcode-solution/
https://leetcode-cn.com/leetbook/read/top-interview-questions-easy/xn854d/
https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof/solution/mian-shi-ti-10-ii-qing-wa-tiao-tai-jie-wen-ti-dong/