题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
求解思路
刚开始是想要通过递归模拟求解,结果超时了。但是这样肯定能求出解来,不过计算了大量重复的代码,复杂度应该是指数级的。
第一次想的正确的思路应该是:
先计算出最多能放几个2步,假设是n个
i从1到n,计算i个2步的情况下步法的组合数,所有组合数累加到sum上
sum+1是最终解,因为全是1的情况也要考虑
复习排列组合的公式:
Cnk=n(n−1)(n−2)⋯(n−k+1)(n−k)(n−k−1)⋯2×1C_{n}^{k}=\frac{n(n−1)(n−2)⋯(n−k+1)}{(n−k)(n−k−1)⋯2×1}Cnk=(n−k)(n−k−1)⋯2×1n(n−1)(n−2)⋯(n−k+1)
提交上述代码后,显示时间是3ms
但是,结合前一题的斐波那契数列和其他dalao的题解,本题目实际上是一个斐波那契数据列的思路!!!更加简介的思路如下:
- 只有一个台阶,步法为1,;有两个台阶步法是2
- 假设走到第那个台阶花费了F(n)F(n)F(n)步;如果之前的一步走了一个台阶,那么之前的步骤是F(n−1)F(n-1)F(n−1)步;如果之前的一部走了两个台阶,那么之前的步骤是F(n−2)F(n-2)F(n−2)步;所以F(n)=F(n−1)+F(n−2)F(n)=F(n-1)+F(n-2)F(n)=F(n−1)+F(n−2)
因此,这种方式比排列组合的思路要简单得多,而且不易出错!!最终版本是这个。
解题代码
#include <bits/stdc++.h>
using namespace std;
// 这是超时的,但是结果正确
class Solution_failed {
public:
int jumpFloor(int number) {
int sum = 0;
if(number == 0) {
return 1;
} else if(number < 0) {
return 0;
} else {
sum += jumpFloor(number - 1); // 跳一个
sum += jumpFloor(number - 2); // 跳两个
return sum;
}
}
};
// 这是AC的代码,使用了组合
class Solution_comp {
public:
int jumpFloor(int number) {
// 只要确定了2步的位置,1步的位置随便插入
int n = number / 2;
int sum = 1;
for(int i = 1; i <= n; ++i) {
// 注意,每增加一个2,总的空位置就要少一个,
int t = comp(number - i, i);
sum += t;
}
return sum;
}
// 计算组合数
int comp(int n, int k) {
long long up = 1, down = 1;
for(int i = n; i >= n - k + 1; i--) {
up *= i;
}
for(int j = k; j >= 1; j--) {
down *= j;
}
return up / down;
}
};
// 最终提交版本
class Solution {
public:
int jumpFloor(int number) {
if(number == 1) {
return 1;
}
if(number == 2) {
return 2;
}
int a = 1, b = 2;
for(int i = 3; i <= number; ++i) {
int t = a;
a = b;
b = t + b;
}
return b;
}
};
// 以下是测试代码
int main() {
Solution_failed sof;
Solution_comp so;
Solution so;
for(int i = 1; i <= 10; ++i) {
cout << sof.jumpFloor(i) << "," << sc.jumpFloor(i) \
<< "," << so.jumpFloor(i) << endl;
}
return 0;
}
运行时间上,数列思路和组合思路都是3ms,而实际上,应该是数列思路更快才对。。。。
本文详细解析了青蛙跳台阶问题的解决思路,包括递归、组合数和斐波那契数列三种方法,并对比了各自的优缺点及运行效率。最终提供了一种简洁高效的斐波那契数列解法。
397

被折叠的 条评论
为什么被折叠?



