跳青蛙问题与变态跳青蛙问题
今天在网上看到两个算法题,分别是跳青蛙问题与变态跳青蛙问题,具体题目如下。
问题
跳青蛙问题:
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
这道题看似简单,但是我看了半天也没想出个突破口,在本子上画来画去也没想到解决的方法。
直到我将台阶的个数于跳法的个数罗列出来才发现端倪:
台阶数 跳法数 1 1 2 2 3 3 4 5 5 8 ... ...
这尼马不就是斐波那彻数列么?
这下问题转变成了,如何求斐波那彻数列?
方法分两种:递归和非递归。
其实递归的方法是更加容易理解的,写起来也是最简单的。我们直到斐波那彻数列的公式:
f(n) = f(n-1) + f(n-2), n >= 2
套用公式就能写出递归的方法:
int func(int number) { if (number <= 0) { return (-1); } else if (1 == number){ return 1; } else if (2 == number) { return 2; } else { return func(number - 1) + func(number - 2); } }
关于递归方法时间复杂度,这里就不做研究了,有兴趣的朋友可以看看这篇博客,讲的非常好,因为我看不懂:
http://www.cnblogs.com/python27/archive/2011/12/09/2282486.html
其实递归方法的效率是非常慢的,如果在面试的时候,明明可以用非递归的方法写出答案,你偏偏要用递归,那你就是做死了(真事儿,我朋友面别人就用这标准)。
下面介绍非递归的方法,先来看看代码:
int func(int number) { if(number<=3) return number; int f2=1; int f1=0; int f=0; for(int i=0;i<number;++i) { f=f1+f2; f1=f2; f2=f; } return f; }
很明显,时间复杂度为O(n),比递归的方法快了很多倍。
这种方法巧妙的利用了求解公式,类似于用了两个指针,分别指向了被求数的前两位数,得到被求数后,再将其值赋予其中一个指针,另一个指针则往前挪。
看过了正常的跳青蛙问题,我们再来看变态的跳青蛙。
具体题目如下:
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
套用吴宗宪大哥的话说就是:哎哟,这个就厉害了。
这次青蛙可以任意的选择跳上的台阶数,所以不再是一个标准的斐波那契数列问题,不过没关系,我们先找寻问题的规律,再从规律寻找突破口。
根据题目,有:
f(0) = 1
f(1) = 1
f(2) = f(2-1) + f(2-2)
f(3) = f(3-1) + f(3-2) + f(3-3)
...
f(n) = f(n-1) + f(n-2) + ... + f(n-(n-1)) + f(n-n)
简单的解释一下:例如f(3-1)表示3阶跳了1阶后,剩下的跳阶方法数,f(3-2)表示3阶跳了两阶后剩下的跳阶方法数,以此类推,直到一次跳n阶后,剩下的跳阶方法数。
现在问题明了了很多,但是还不够,我们可以继续对其进行分解:
因为 : f(n) = f(n-1) + f(n-2) + ... + f(n-(n-1)) + f(n-n) = f(0) + f(1) + f(2) + ... + f(n-2) + f(n-1)
所以 : f(n-1) = f(0) + f(1) + ... + f((n-1)-1) = f(0) + f(1) + f(2) + ... + f(n-2)
则: f(n) = f(n-1) + f(n-1) = 2*f(n-1)
现在可以根据这个式子来写出代码了。
同样,我们先写出容易写的递归方法:
int func(int number) { if (number <= 0) { return -1; } else if (number == 1) { return 1; } else { return 2 * func(number - 1); } }
然后是非递归的方法:
int func(int number) { if (number <= 0) { return (-1); } if (1 == number) { return 1; } int f1 = 1; int f = 0; for (int i = 0; i < number - 1; i++) { f = 2 * f1; f1 = f; } return f; }
总结
通过对这两个问题的分析和解决,我深刻的明白了一个道理:解决问题之前,我们必须充分的了解问题,把握问题的规律。科学家们一直致力于寻找物质的规律,世界的规律以及宇宙的规律。而算法的美妙之处就在于,你通过不断的训练,能从纷杂的问题表面分析出实质性的规律,就如同在茫茫互联网海洋中,寻找那一段段神秘的代码。
今天的博客就写道这里了,老司机催我上车了。