【LeetCode刷题记录】简单篇-70-爬楼梯

【题目描述】

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?


【测试用例】

示例1:

        输入:n = 2

        输出:2

        解释:有两种方法可以爬到楼顶。

                1.1阶 + 1阶

                2.2阶

示例2

        输入:n = 3

        输出:3

        解释:有三种方法可以爬到楼顶

                1.1阶 + 1阶 + 1阶

                2.1阶 + 2阶

                3.2阶 + 1阶


【思路分析】

这道题也算是一道很经典的题,读大学的时候学过,但不记得是在什么课上学过。用了两种方法求解。

先说一下这里的规律,一共n阶楼梯,每次只能走1阶或者2阶。

当n=1时,即爬1阶楼梯时,无疑只有一种方法,走1阶即可;

当n=2时,有两种方法,可以一次走2阶,也可以分两次每次走1阶;

当n=3时,爬3阶楼梯,可以从第1阶走2阶到第3阶,也可以从第2阶走1阶到第3阶,以此类推。换句话说就是,n>=3时,爬到n阶所用的方法总数可以由爬到n-1阶和爬到n-2阶推算出来,如果用func(n)表示爬n阶台阶的方法数,则func(n) = func(n-1) + func(n-2)

法一:递归

递归方法,在代码中表现为函数的自身嵌套,这也是很好想到的一种方法。刚才讲了这道题的本质规律func(n) = func(n-1) + func(n-2),在代码中func就是求方法数的函数climbStairs(n)

当n<=2时,单独处理,直接返回n;

当n>2时,返回climbStairs(n-1) + climbStairs(n-2)。

ps:递归方法在力扣中提交时,C实现可以正常AC,但是C++实现会提示超时,可能力扣对这道题设置了时间?或者我代码没写对?想了半天也没找到原因。

法二:动态规划

动态规划是一种常见的算法思想,它是一种解决多阶段决策问题的优化方法。核心思想是将原问题分解为若干个相同的子问题,分别求解这些子问题并将其结果保存下来,可以有效避免重复计算,极大提升算法效率。

在本题中,爬n阶楼梯是原问题,爬n-1阶、n-2阶....1阶楼梯都是相同的子问题,他们的解决办法相同,只需要分别解决这些问题并将结果保存在一个数组fun中,那么 fun[i] 就是爬 i 阶楼梯的方法数,最后返回fun[n]即可。

这个数组也很好求,首先fun[1]=1,fun[2]=2(fun[0]不用管,可以为0也可以为1也可以任意值,为0表示站在0阶楼梯自然也不需要什么方法爬到0阶楼梯,为1可以理解为fun[2] = fun[1] + fun[0]的计算,这时遍历就是从2开始的),从fun[3]开始遍历,每个位置都等于其前两个位置的和。

空间复杂度优化

上面动态规划的空间复杂度是O(n),实际上可以优化为O(1)。O(n)是因为创建了一个长度为n的数组,但是实际上我们只需要两个变量one和two分别存储n=1和n=2时的方法数,然后在接下来的循环中,不断更新one和two的值:

①临时变量tmp=one+two (这里的tmp相当于刚才的fun数组中的每个位置的值,只是这里不用存储,只起临时中转的作用),②one=two,③two=tmp

使one和two始终存储着对应当前n值的func[n-2]和func[n-1](func表示爬n阶楼梯的方法数,这里只是方便说明而用这个符号)

举个例子,假如n=3,那么fun[3] = fun[2] + fun[1],而one对应的就是fun[1],two对应的就是fun[2],tmp=one+two也就是在计算fun[3]。而在n=4时,需要fun[3]和fun[2],代码中one=two就相当于让one指向了fun[2],代码中two=tmp就相当于让two指向了fun[3],就这样,在一轮轮的循环中,不用额外开辟空间存储每个n的结果,循环结束后two中保存的就是fun[n]的值,就达到了优化空间复杂度的目的。


【参考代码】

法一:C实现

#include <stdio.h>

//easy-70-爬楼梯
int climbStairs(int n);

int main(){
	int n;
	scanf("%d", &n);
	int res = climbStairs(n);
	printf("%d\n", res);
	return 0;
}

//法一:递归
int climbStairs(int n) {
	if(n<=2){
		return n;
	}else{
		return climbStairs(n-1) + climbStairs(n-2);
	}
}

法二:C实现

#include <stdio.h>

//easy-70-爬楼梯
int climbStairs(int n);

int main(){
	int n;
	scanf("%d", &n);
	int res = climbStairs(n);
	printf("%d\n", res);
	return 0;
}

//法二:动态规划
int climbStairs(int n) {
	if(n <= 2){
		return n;
	}
	int fun[n+1];
	fun[1] = 1;
	fun[2] = 2;
	int i;
	for(i=3;i<n+1;i++){
		fun[i] = fun[i-1] + fun[i-2];
	}
	return fun[n];
}

法二优化:C实现

#include <stdio.h>

//easy-70-爬楼梯
int climbStairs(int n);

int main(){
	int n;
	scanf("%d", &n);
	int res = climbStairs(n);
	printf("%d\n", res);
	return 0;
}

//法二:动态规划优化
int climbStairs(int n) {
	if(n <= 2){
		return n;
	}
	int one = 1;
	int two = 2;
	int i;
	for(i=3;i<n+1;i++){
		int tmp = one + two;
		one = two;
		two = tmp;
	}
	return two;
} 

法二:C++实现

#include <iostream>
#include <vector>
using namespace std;

//easy-70-爬楼梯
class Solution {
public:
    int climbStairs(int n);
};

//法二:动态规划 
int Solution::climbStairs(int n){
	if(n <= 2){
		return n;
	}
	vector<int> fun(n+1);
	fun[1] = 1;
	fun[2] = 2;
	int i;
	for(i=3;i<n+1;i++){
		fun[i] = fun[i-1] + fun[i-2];
	}
	return fun[n];
}

int main(){
	int n;
	cin>>n;
	Solution sol;
	int res = sol.climbStairs(n);
	cout<<res<<endl;
	return 0;
}

法二优化:C++实现

#include <iostream>
using namespace std;

//easy-70-爬楼梯
class Solution {
public:
    int climbStairs(int n);
};

//动态规划优化 
int Solution::climbStairs(int n){
	if(n <= 2){
		return n;
	}
	int one = 1;
	int two = 2;
	int i;
	int tmp;
	for(i=3;i<n+1;i++){
		tmp = one + two;
		one = two;
		two = tmp;
	}
	return two;
}

int main(){
	int n;
	cin>>n;
	Solution sol;
	int res = sol.climbStairs(n);
	cout<<res<<endl;
	return 0;
}

  • 35
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值