leetcode之Climbing Stairs爬楼梯

题目链接
中文版题目链接

昨夜走在校园的小路上,灵感乍现,突然明白了为什么刚好是斐波那契数列可解此题。

普通思维:
走第一步时有两种情况,走一个台阶,或两个台阶;

走第二步时,第一步时的两种情况中又分别有两种情况;
如此递归......

最多走n步即可,所有情况为2^n次;
然后找出少于或等于n步时经过台阶数也刚好为n个的数量即为所求。
(为什么走n步即可?考虑到每步都只走一个台阶情况!)

代码如下:

int N;
int Num;
void recursion(int count, int step) {//count记录走过台阶个数,step为步数
    //printf("%d %d\n", count, step);
    if (step > N || count > N) {
        return;
    } else if (count == N) {
    	Num++;
    	return;
    }
    recursion(count+1, step+1);//一步一个台阶
    recursion(count+2, step+1);//一步两个台阶
}

int climbStairs(int n) {
    N = n;
    Num = 0;
    recursion(0, 0);
    return Num;
}
结果:
超时!n为35时,就有点力不从心了。

逆向思维:
假设有20个台阶,即n=20;
则可以发现到达第20阶有两种情况19 + 1与18 + 2;
设到第n个台阶方法有f(n)种,则:
f(20) = f(19) + f(18);
f(19) = f(18) + f(17);
f(18) = f(17) + f(16);
如此循环......
f(3)=f(2)+f(1);
f(2)=f(1)+f(0);
f(1)=1

f(0)=1
其实到此已不难发现刚好是斐波那契数列,但为什么一定要用斐波那契数列?

此时又可使用递归

递归代码如下:

int f0 = 1;
int f1 = 1;
int climbStairs(int n) {
	int count = 0;
    if (n == 1 || n == 0) {
        return 1;
    }
    count = climbStairs(n-1) + climbStairs(n-2);
    return count;
}
结果:
性能貌似提升了一倍,但依旧超时!

问题所在:不难发现,使用此种递归的话,会出现很多重复计算的地方;
比如f(20) = f(19) + f(18) 与 f(19) = f(18) + f(17)
就重复计算了f(18),那么找到问题所在,就好解决了;
我们只需在计算之后记录f(18),下次再遇到需要f(18)之处就无需计算,直接使用即可!
考虑到答案在int范围之类,n最大取值貌似就是45了,故可以开数组空间记录f(1)~f(n-1);

以下代码没有开数组存。
代码如下
int climbStairs(int n) {
    int f0 = 1, f1 = 1, f2 = 1;
    for (int i = 2; i <= n; i++) {
        f2 = f0 + f1;
        f0 = f1;
        f1 = f2;
    }
    return f2;
}
结果:
性能上有很大提升,图为n=44;


猜你喜欢

转载自blog.csdn.net/qq_36326947/article/details/79620111