有趣的算法-兔子序列
题目:
假设第1个月有1对刚诞生的兔子,第2个月进入成熟期,第3个月开始生育兔子,而1对成熟的兔子每月会生1对兔子,兔子永不死去。那么,由1对初生兔子开始,12个月后会有多少对兔子呢?
分析:
以1对新出生小兔子为例,
第1个月,小兔子1没有繁殖能力,所以还是1对。
第2个月,小兔子1进入成熟期,还是1对。
第3个月,小兔子1生了1对小兔子2,本月共有2对兔子。
第4个月,小兔子1又生了1对小兔子3,本月共有3对兔子。
第5个月,小兔子1又生了1对小兔子4,而在第3个月出生的小兔子2也生了1对小兔子5,本月共有5对兔子。
第6个月,小兔子1,2,3各生1对小兔子,本月共有8对兔子。
以此类推,可以得出如下关系:
当月兔子对数 = 上月兔子对数 + 上上月兔子对数。不难得出,该问题符合斐波那契数列规律。
所以很容易得出实现:
//算法1
int fib(int n)
{
if(n<1)
return -1;
if(n==1 || n==2)
return 1;
return fib(n-1) + fib(n-2);
}
但由于是递推实现,算法复杂度较高,感兴趣的可以自行计算一下,这里略过。
所以进行算法优化:
//算法2
int fib(int n)
{
if(n<1)
return -1;
int *a=new int[n];
a[1]=1;
a[2]=1;
for(int i=3; i<n; i++)
a[i] = a[i-1] + a[i-2];
return a[n];
}
该算法不再使用递归求解,而是使用数组进行存储中间变量,这样将算法的时间复杂度大大降低,从指数级降到了多项式级,当然也增加了空间复杂度。那还有没有更好的方式进行优化,既能降低时间复杂度,又不增加空间复杂度?
这里可以考虑迭代法,进行辗转相加法来实现:
//算法3
int fib(int n)
{
int sum1, sum2;
if(n<1)
return -1;
if(n==1 || n==2)
return 1;
s1 = 1;
s2 = 1;
for(int i=3; i<=n; i++)
{
s2 += s1; //辗转相加
s1 = s2 - s1;//记录前一项
}
return s2;
}
此方法不再使用数组,而是使用辅助变量,将空间复杂度从O(n)降到了O(1)。
以上,同一个问题,稍加变换,得到的算法性能就大大不同,这正是算法之美所在。据了解,斐波那契数列的时间复杂度还可以从多项式级降到对数级,有兴趣的可以自行查阅资料。
一步,一步,一步...
回头看,已不见起点!

浙公网安备 33010602011771号