uTank-木头
每一个你不满意的现在,都有一个你没有努力的曾经。

【题目描述】

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

 

posted on 2021-04-25 15:05  uTank  阅读(85)  评论(0编辑  收藏  举报