爬梯子问题的两种解法DFS和DP

想着学习DP来着,看见一个例题,自己下意识就是深搜解题,所以吧两种解法都在这里贴上

爬梯子问题

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

解法1:DFS

代码:

#include<iostream>

using namespace std;
int c=0;
int n;
void dfs(int current){
	if(current==n){
		c++;
		return;
	}
	if(current>n)
		return;
	
	//走一阶
	current++;
	if(current<=n)
		dfs(current);
	current--;
	//走两阶
	current+=2;
	if(current<=n)
		dfs(current);
	current-=2;

	return;
}

int main(){
	ios::sync_with_stdio(false);

	cin>>n;
	dfs(0);
	cout<<c<<endl;
	return 0;
}

这是一个很简单的深搜解法,可以吧问题想象成一颗二叉树,每次面临两种选择,走一阶还是走两阶。当变量current大于N时候,说明这条路行不通,当变量current刚好等于N时,说明这是一种解法,变量c加一。
每次递归之前先判断当然的current是否已经大于或等于N,如果为真就不用进行下一步的递归操作。(剪枝操作)

在这里插入图片描述
如图所示,我们从最顶上的节点开始向下走,每次面临两个选择方向,一阶和二阶。
图中的黑色线路表示可行线路,蓝色表示不可行线路,最终会得到三条使得current等于N的路线,即答案为3。
此方法的效率太低,我测试了N=40的情况,跑了一分多钟才出结果,所以这个方法pass

方法2:DP

#include<iostream>

using namespace std;
int main(){
	ios::sync_with_stdio(false);
	
	int n;
	cin>>n;
	
	int p[100];
	p[0]=0;p[1]=1;p[2]=2;

	if(n<3){
		cout<<p[n]<<endl;
		return 0;
	}

	for(int i=3;i<=n;i++){
		p[i]=p[i-1]+p[i-2];

	cout<<p[n]<<endl;
	return 0;
}

典型的以空间换时间的思想,吧之前到达每一阶的所有方法总和保存起来,这样到达N阶,就只与N-1阶和N-2阶有关。
因此我们可以推导出递推公式:

dp[n]=dp[n-1]+dp[n-2]

可见当计算到达第N阶的方法总数时,需要提前知道前两阶的方法总数,于是我们提前定义

dp[1]=1;
dp[2]=2;

用以计算方便

此方法效率高(N=40,秒出结果),但是牺牲了空间,作为一个强迫症患者,我的编程风格是尽量能省就省,于是改进了一下

DP+环形队列

代码如下:

#include<iostream>

using namespace std;
int main(){
	ios::sync_with_stdio(false);

	int n;
	cin>>n;

	int *p=new int[2];
	p[0]=1;p[1]=2;

	int pointer=0;
	
	if(n<3){
		cout<<p[n-1]<<endl;
		return 0;
	}

	for(int i=3;i<=n;i++){
		p[pointer]=p[pointer]+p[(pointer+1)%2];
		pointer=(pointer+1)%2;
	}

	cout<<p[(pointer+1)%2]<<endl;
	return 0;
}

运行结果:
在这里插入图片描述

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_Dizzrt

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

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

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

打赏作者

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

抵扣说明:

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

余额充值