【算法与数据结构】70、LeetCode爬楼梯

本文详细解析了LeetCode中的爬楼梯问题,介绍了基本版本的动态规划解法,包括递归过程和空间复杂度优化。同时扩展到爬楼梯进阶版,将其转化为完全背包问题并提供相应的代码实现和复杂度分析。
摘要由CSDN通过智能技术生成

所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解

一、题目

在这里插入图片描述

二、解法

  思路分析:因为每次可以爬1阶或者2阶台阶,若想到达第i阶,则有两种情况:在第i-2阶台阶处一次爬2阶(如果一次一阶爬两次到第i阶的情况属于后面一种),或者是在第i-1阶一次爬1阶。假设dp数组代表到达第i阶的方法,那么根据上述分析,有 d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] dp[i]=dp[i-1]+dp[i-2] dp[i]=dp[i1]+dp[i2]
  程序如下

class Solution {
public:
	int climbStairs(int n) {		// 1 1 2 3 5 8 13 21
		//if (n < 1) return 0;		// n在[1,45]之间
		vector<int> dp(n + 1);	// 动态规划中的dp数组
		dp[0] = 1;
		dp[1] = 1;
		for (int i = 2; i <= n; i++) {
			dp[i] = dp[i - 1] + dp[i - 2];
		}
		return dp[n];
	}
};

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

  同样,我们只用到了两个数,进行算法优化,将空间复杂度降低到O(1)。程序如下

class Solution {
public:
	int climbStairs(int n) {		// 1 1 2 3 5 8 13 21
		//if (n < 1) return 0;		// n在[1,45]之间
		vector<int> dp(n + 1);	// 动态规划中的dp数组
		dp[0] = 1;
		dp[1] = 1;
		for (int i = 2; i <= n; i++) {
			dp[i] = dp[i - 1] + dp[i - 2];
		}
		return dp[n];
	}
};

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)

三、完整代码

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

//class Solution {
//public:
//	int climbStairs(int n) {		// 1 1 2 3 5 8 13 21
//		//if (n < 1) return 0;		// n在[1,45]之间
//		vector<int> dp(n + 1);	// 动态规划中的dp数组
//		dp[0] = 1;
//		dp[1] = 1;
//		for (int i = 2; i <= n; i++) {
//			dp[i] = dp[i - 1] + dp[i - 2];
//		}
//		return dp[n];
//	}
//};

class Solution {
public:
	int climbStairs(int n) {
		int dp[2] = {1, 1};
		for (int i = 2; i <= n; i++) {
			int sum = dp[0] + dp[1];
			dp[0] = dp[1];
			dp[1] = sum;
		}
		return dp[1];
	}
};

int main() {
	int n = 4;
	Solution s1;
	int result = s1.climbStairs(n);
	cout << result << endl;
	system("pause");
	return 0;
}

四、爬楼梯进阶版

  改为:一步一个台阶,两个台阶,三个台阶,…,直到 m个台阶。问有多少种不同的方法可以爬到楼顶呢?

  实际上,改动后的题目可以抽象成一个完全背包的问题,1阶,2阶,… m阶就是物品,楼顶就是背包。每一阶可以重复使用,例如跳了1阶,还可以继续跳1阶。然后根据完全背包的思路,写出如下代码:

#include <iostream>
#include <vector>
using namespace std;
int main() {
	int n, m;
	while (cin >> n >> m) {
		vector<int> dp(n + 1, 0);
		dp[0] = 1;
		for (int i = 1; i <= n; i++) { // 遍历背包
			for (int j = 1; j <= m; j++) { // 遍历物品
				if (i - j >= 0) dp[i] += dp[i - j];
			}
		}
		cout << dp[n] << endl;
	}
	system("pause");
	return 0;
}

复杂度分析:

  • 时间复杂度: O ( m ∗ n ) O(m*n) O(mn)
  • 空间复杂度: O ( n ) O(n) O(n)
    end
  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晚安66

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值