【斐波那契数列】
fibonacci数列,斐波那契数列,又称黄金分割数列。
在数学上,费波那西数列是以递归的方法来定义:
用文字来说,就是费波那西数列由 0 和 1 开始,之后的费波那西系数就由之前的两数相加。
特别指出:0不是第一项,而是第零项。
通项公式:
【求解斐波那契数列】
解法一:递归求解
对于求解斐波那契数列,最直接的方法就是根据定义用递归方法来实现。但是这种方法算法复杂度高(n的指数级别),效率低。由于递归方法中存在着大量的重复计算,当n较大时,计算量将特别大。
//递归方法求解
long fib_recursion( int n )
{
if( n == 0 ) return 0;
if( n == 1 ) return 1;
return fib_recursion(n - 1) + fib_recursion(n - 2);
}
long fib_recursion( int n )
{
if( n == 0 ) return 0;
if( n == 1 ) return 1;
return fib_recursion(n - 1) + fib_recursion(n - 2);
}
解法二:开辟n+1的数组
为了避免重复计算,我们可以采用数组来存储已经计算过的数值,避免重复计算。这样算法的时间复杂度大大降低,变为O(n).缺点是要动态开辟数组,空间复杂度较高。
//开辟数组求解
long fib_mem( int n )
{
if(n < = 0)
return 0;
else if(n == 1)
return 1;
else
{
//动态创建一个长度为(n+1)的数组
int *arry = new int[n + 1];
arry[ 0] = 0;
arry[ 1] = 1;
for( int i = 2;i < =n;i ++)
{
arry[i] =arry[i - 1] +arry[i - 2];
}
int result =arry[n];
delete [] arry; //释放空间
return result;
}
}
long fib_mem( int n )
{
if(n < = 0)
return 0;
else if(n == 1)
return 1;
else
{
//动态创建一个长度为(n+1)的数组
int *arry = new int[n + 1];
arry[ 0] = 0;
arry[ 1] = 1;
for( int i = 2;i < =n;i ++)
{
arry[i] =arry[i - 1] +arry[i - 2];
}
int result =arry[n];
delete [] arry; //释放空间
return result;
}
}
解法三:动态规划,设置临时变量保存上一步计算的数值
设置两个临时变量保存f(n-1)和f(n-2)的值,这样时间复杂度为O(n),空间复杂度为O(1)
//动态规划
int fib_dp( int n )
{
long first = 0;
long second = 1;
int sum ;
for ( int i = 0; i <n - 1; ++i)
{
sum = first + second;
first = second;
second = sum;
}
return sum;
}
解法四:公式法
利用fibonacci的一般表达式,我们可以直接求解。这是最快的方法,复杂度为O(1)。
//公式法求解
int fib_binet( int n)
{
return ( pow( ( 1 +pow( 5, 0. 5)),n ) - pow( ( 1 -pow( 5, 0. 5)),n )) /(pow( 2. 0,n) *pow( 5, 0. 5));
}
完整代码
# include <iostream >
# include <time.h >
# include <math.h >
using namespace std;
//递归求解
int fib_recursion( int n )
{
if( n == 0 ) return 0;
if( n == 1 ) return 1;
return fib_recursion(n - 1) + fib_recursion(n - 2);
}
//使用数组存放数列中的每一个值
int fib_mem( int n )
{
if(n < = 0)
return 0;
else if(n == 1)
return 1;
else
{
//动态创建一个长度为(n+1)的数组
int *arry = new int[n + 1];
arry[ 0] = 0;
arry[ 1] = 1;
for( int i = 2;i < =n;i ++)
{
arry[i] =arry[i - 1] +arry[i - 2];
}
int result =arry[n];
delete [] arry; //释放空间
return result;
}
}
//动态规划
int fib_dp( int n )
{
long first = 0;
long second = 1;
int sum ;
for ( int i = 0; i <n - 1; ++i)
{
sum = first + second;
first = second;
second = sum;
}
return sum;
}
//binet给出了一个公式可以计算数列,比任何动态规划算法都快,但是这样的公式可欲不可求
int fib_binet( int n)
{
return ( pow( ( 1 +pow( 5, 0. 5)),n ) - pow( ( 1 -pow( 5, 0. 5)),n )) /(pow( 2. 0,n) *pow( 5, 0. 5));
}
//测试代码
int main()
{
int n ;
cout << "请输入要求解的fibonacci数" <<endl;
cin >>n;
clock_t timebegin, timeend;
timebegin = clock();
int sum_recursion = fib_recursion(n);
timeend = clock();
cout << "sum_recursion = " << sum_recursion << " 用时" <<timeend -timebegin << endl;
timebegin = clock();
int sum_mem = fib_mem(n);
timeend = clock();
cout << "sum_mem = " << sum_mem << " 用时" <<timeend -timebegin << endl;
timebegin = clock();
int sum_dp = fib_dp(n);
timeend = clock();
cout << "sum_dp = " << sum_dp << " 用时" <<timeend -timebegin << endl;
int sum_binet = fib_binet(n);
cout << "sum_binet= " << sum_binet <<endl;
return 0;
}
【斐波那契数列应用实例】
1.一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个n级的台阶总共有多少种跳法。
解题思路:此题本质上就是求解fibonacci数列第n项的值。若n=1,则f(1)=1;若n=2,则f(2)=2;若n=3,可以这样考虑青蛙若最后一跳可以跳一级,则方法为数为f(2),若最后一跳跳2级,则方法数为f(1),因此f(3)=f(1)+f(2)。所以当n>=3时,f(n)=f(n-1)+f(n-2);所以本题就是求解fibonacci数列第n项的值。