0
点赞
收藏
分享

微信扫一扫

上楼梯(递归和迭代的对比)

Greatiga 2022-02-12 阅读 89
算法

题目:

一个小孩上楼梯,楼梯有n阶,小孩每次可以上一阶,两阶或三阶,问一共有几种走法(约定n为0是方法数为1)。

输入在一行给出n。答案对1e9^7取模。

输出在一行给出方法数。

思路:

这是一道很经典的题目,此前也遇到过很多次,但每次回头看都会有一些不一样的想法。要解决这道题,首先肯定是从阶数较小的开始分析。

如果只有一阶楼梯,方法显然只有1种。

如果有两阶楼梯,有2种方法。一种是一次走两阶。一种是先走一阶,再走一阶。

如果有三阶楼梯,则有4种方法。一种是一次走三阶。一种是先走一阶,此时剩下两阶,而两阶的方法数已经算出是两种。还有一种是先走两阶,再走一阶。

如果有四阶楼梯,则有7种方法。一种是先走一阶剩下三阶,三阶的方法数为4种。一种是先走两阶剩两阶,两阶的方法数是2种。一种是先走三阶剩一阶,方法数为1种。所有相加就是7种。

如果有五阶楼梯也是如此,分析先走一阶剩四阶的方法数,先走两阶剩三阶的方法数,先走三阶剩两阶的方法数,最后相加即可。

简单归纳就可得出,求上n阶楼梯的方法数就是将上n-1,n-2,n-3阶楼梯的方法数相加,写成公式就是:

f(n) = f(n-1) + f(n-2) + f(n-3)

递归代码如下,时间复杂度为O(n^3):

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
int recursion1(int n);
int recursion2(int n);
int main() {
	int n;
	cin >> n;
	cout << recursion2(n) << endl;
	return 0;
}

int recursion1(int n) {
	if(n<0) return 0;
	else if(n==0 || n==1) return 1;
	else if(n==2) return 2;
	return recursion(n-1)%mod + recursion(n-2)%mod + recursion(n-3)%mod; 
}

同样的思路,用迭代的方式代码如下,时间复杂度为O(n):

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
int recursion2(int n);
int main() {
	int n;
	cin >> n;
	cout << recursion2(n) << endl;
	return 0;
}

int recursion2(int n) {
	if(n<0) return 0;
	else if(n==0 || n==1) return 1;
	else if(n==2) return 2;
	int x1 = 1;
	int x2 = 2;
	int x3 = 4;
	for(int i=4;i<=n;i++) {
		int t = x1;
		x1 = x2 % mod;
		x2 = x3 % mod;
		x3 = (x1+x2)%mod + t%mod;
	}
	return x3;
}

分析从思考到产生代码的过程:

思考时是从小规模开始,我们能解决的问题顺序思考的,这与迭代的代码完全吻合,而递归则是多了一步归纳,将思路总结成递归式表达出来,单看式子,是一个逆序的过程,仿佛是从大规模开始求,(如果一开始思考是从大规模开始分析,这种思想是分治思想),显然从小规模开始更符合人脑的思考方式,而产生的两种代码,只是同一种思路不同的表现方式。

递归的代码在求解问题时并非先求解大规模问题,也是通过层层递归,先求解小规模问题,再层层返回,得出结果,而每一次递归,都会在栈中为其开辟空间,储存变量。所以从性能上分析,就本题而言,迭代是更好的解法,递归好在表达更加简洁。

举报

相关推荐

0 条评论