【3】70.爬楼梯

70.爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。

示例 :
输入: 3
输出: 3

解法一:递归
很明显是一个递归的题目,我们可以很轻松地写出这样的代码。
我们知道,当还剩0级时,方法为0,
还剩1级时,方法为1,即1个台阶直接上去。
还剩2级时,方法为2,一次2个台阶或者两次1个台阶。
因此若n<=2直接返回n。

int climbStairs(int n)
{
    if(n<=2) return n;
    return climbStairs(n-1)+climbStairs(n-2);
}

但是这样产生了大量重复计算,很容易就超时了,因此需要寻找效率更高的算法。
时间复杂度为O(2^n)

解法二:循环求和
分析上面的代码,可以知道这就是一个斐波那契数列,第三项的值等于前两项之和,因此我们可以直接按照斐波那契数列求和。

class Solution {
public:
    int climbStairs(int n)
{
    if(n<=2) return n;
    int p=1,q=2,ans=0;
    for(int i=2;i<n;++i)
    {
        ans=p+q;
        p=q;
        q=ans;
    }
    return ans;
}
};

这样就可以通过测试。
但是我转念一想,不太对,我做这道题是为了学习动态规划呢,前面好像都不是,还得有另一种解法。

解法三:动态规划(自底向上)
这种方法和解法二大致相同,但是采用了动态规划的思想,即将小规模的问题答案储存起来,最后用于大规模问题的解答。

int climbStairs(int n) {
		int* dp = new int[n + 1];
		dp[1] = 1;
		dp[2] = 2;
		for (int i=3; i<=n; i++)
		{
			dp[i] = dp[i - 1] + dp[i - 2];
		}
		return dp[n];
	}

解法四:动态规划(带备忘录的自顶向下)

int climb_Stairs(int i, int n, int dp[]) {
    if (i > n) {
        return 0;
    }
    if (i == n) {
        return 1;
    }
    if (dp[i] > 0) {
        return dp[i];
    }
    dp[i] = climb_Stairs(i + 1, n, dp) + climb_Stairs(i + 2, n, dp);
    return dp[i];
}

int climbStairs(int n) {
        int *dp = new int[n + 1];
        return climb_Stairs(0, n, dp);
    }

解法五:套公式
在看别人的解法的时候发现了一个更奇妙的方法,时间复杂度也更低,运用了斐波那契数列的直接计算公式

F n = 1 / 5 [ ( 1 + 5 2 ) n ( 1 5 2 ) n ] Fn=1/\sqrt5[(\cfrac{1+\sqrt5}{2})^n-(\cfrac{1-\sqrt5}{2})^n]

  • 时间复杂度为O(logn)
class Solution {
    public:
     int climbStairs(int n) {
        double sqrt_5 = sqrt(5);
        double ans=pow((1 + sqrt_5) / 2, n +1) -pow((1 - sqrt_5) / 2,n+1);
        return (int)(ans/ sqrt_5);
    }
};

方法任选一种即可

发布了6 篇原创文章 · 获赞 2 · 访问量 117

猜你喜欢

转载自blog.csdn.net/weixin_43934036/article/details/104270183