First Article

本文介绍了斐波那契数列的理论背景,以及如何通过数组、循环、递归、递推等编程方法计算数列,重点讲解了递归优化以提高效率,同时提及了高精度算法的应用。

本站首文,主要是斐波那契数列的讨论。

斐波那契数列,也就是兔子数列,上故事(谢谢bing):

一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死:

我们不妨拿新出生的一对小兔子分析一下:

第一个月小兔子没有繁殖能力,所以还是一对

两个月后,生下一对小兔对数共有两对

三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对

我们接着往下算,就会得到形如1,1,2,3,5,8……(或0,1,1,2……)的一个数列,,也就是说,每一项都是由前两项的和得来的,得出数学上的求通项公式也是很容易的,也就是an=1/√5[(1+√5)n/2-(1-√5)n/2]这个简单的式子(推了一个晚自习),但是毕竟是一道OJ上的题目,所以我们就要用编程的角度去实现,毕竟gg说过:我们是负责想的,电脑是负责算的。

数组思想

我们不妨从最开始定义一个数组叫做fb[10000],然后人为的初始化fb[1]和fb[2],然后用一个for循环依次带入到fb[n]就可以了,但是有一个无法解决的缺点就是——数组是有大小的,相比较而言,会容易爆,上代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a[30],n;
	scanf("%d",&n);
	a[1] = a[0] = 1;
	for(int i = 2;i <= n; i++)
	{
		a[i] = a[i - 2] + a[i - 1];
	}
	printf("%d",a[n - 1]);
	return 0;
}

循环思想

其实,循环的思想和数组或者接下来的递归递推思想是很像的,他在这里起到一个承上启下的作用,这就是我为什么要在这里写出他的原因.其实循环也并不难,首先函数肯定是离不开的,所以我们定义一个叫做fb的函数(注意,一定是int型的,因为要返回值),然后对于边界n=1,n=2的限定,然后从3开始循环,定义一个last1,last2和sum,使sum=last1+last2,然后使三者分别赋值就可以,在main函数里fb(n)就行了,好,上代码:

#include<bits/stdc++.h>
using namespace std;
int fb(int n)
{
	if (n == 1)
	{
		return 1;
	}
	if (n == 2)
	{
		return 1;
	}
	int last1 = 1;
	int last2 = 1;
	int sum = 0;
	for (int i = 3; i <= n; i++){
		sum = last1 + last2;
		last2 = last1;
		last1 = sum;
	}
	return sum;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	printf("%d\n", fb(n));
	return 0;
}

递归思想

递归的本质是自己调用自己,所以只要定义边界fb(1),fb(2),就可以了,然后return fb(n)=fb(n-1)+fb(n-2);上代码:

#include<bits/stdc++.h>
using namespace std;
int fb(int n)
{
	if(n == 1)//1边界 
	return 1;
	if(n == 2)//2边界 
	return 1;
	else
	return fb(n - 1) + fb(n - 2);//递归式 
}
int main()
{
	int k; 
	scanf("%d",&k);
	fb(k);
	printf("%d\n",fb(k));
	return 0;
}

递推思想

关于递推和递归,其实就本问题而言,表达式是一样的,直接看代码吧:

#include<bits/stdc++.h>
using namespace std;
int fb(int n)
{
    int f0 = 0,f1 = 1,f;
    if(n == 0 || n == 1)
    {
        return n;
    }
    for(int i = 2;i <= n; i++)
    {
        f = f0 + f1;       
        f0 = f1;         
        f1 = f;        
    }            
    return f;
}
int main()
{
    int n;
    scanf("%d",&n);
    printf("%d\n",fb(n));
    return 0;
}

递归的优化(Half an Hour)

不难看出,上面的时间复杂度还是太高,所以我又对递归进行了优化,降低到了线性级别,是属于灵感迸发,上代码:

#include<bits/stdc++.h>
const int MAX=101;//上网搜的,否则爆 
using namespace std;
int a[MAX];
int fb(int n)
{
    if(a[n] != -1) 
	return a[n];
    else
    {
    	a[n] = fb(n - 1) + fb(n - 2);
    	return a[n];
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 0;i <= MAX - 1; i++)
    {
        a[i] =- 1;
    }
    a[0] = 0;
	a[1] = 1;
    cout << fb(n);
    return 0;
}

高精度算法

感谢老版一本通吧,上代码,这个真的不是自己做的:

#include<bits/stdc++.h>
using namespace std;
char sum[1200];
int s = 0,m = 0,n;
int main()
{
    scanf("%d",&n);
    string s1,s2;
    int a[1200],b[1200];
    int he,i;
    s1 = "0";
    s2 = "1";
    for(m = 2;m < n+1; m++)
    {
        memset(a,0,sizeof a);
        memset(b,0,sizeof b);
        a[0] = s1.length();
        for(i = 1;i <= a[0]; i++)
        {
            a[i] = s1[a[0] - i] - '0';
        }
        b[0] = s2.length();
        for(i = 1;i <= b[0]; i++)
        {
            b[i] = s2[b[0] - i] - '0';
        }
        he = (a[0] > b[0] ? a[0] : b[0]);
        for(i = 1;i <= he; i++)
        {
            a[i] += b[i];
            a[i+1] += a[i]/10;
            a[i] %= 10;
        }
        he++;
        while((a[he] == 0) && (he > 1))
        he--;
        for(i = he,s = 0;i >= 1; i--,s++)
        {
        	sum[s] = a[i] + '0';
        }
        s1 = s2;
        s2 = sum;
    }
	cout << s2;
    return 0;
}

总结

斐波那契数列作为函数的入门题型,虽说好想,但是优化起来还是很难的,而且他的变式也是很多,所以说掌握还是很重要的!

公元2023年11月27日

宇宙-拉尼亚凯亚超星系团-室女座星系团-本星系群-银河系-猎户臂-古尔德带-本地泡-本星际云-奥尔特云-太阳系第三行星-地球-中华人民共和国-辽宁省-大连市-中山区——著

Merlin-Aquarius-Mark-Uranus-Lee

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值