斐波那契数列(Fibonacci sequence)
又称黄金分割数列,因数学家莱昂纳多·斐波那契(LeonardodaFibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义: F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)
非递归
循环迭代算法
#include<iostream>
using namespace std;
int main(){
int a = 0,b=1;
int n;
cin >> n;
while(n--){
cout << a << ' ';
int t = a; //把a给一个盒子
a = b; //把b给a
b = t + b; //让b做加法,传给a,输出a,t的作用是存之前的a给b计算
}
return 0;
}
递归算法
#include<iostream>
using namespace std;
int f(int n){
if(n==0) return 0;
else if(n <= 2) return 1;
else return (f(n-2) + f(n-1);
}
int main(){
int n ;
cin >> n;
cout << f(n) << endl;
return 0;
}
由于每次递归都需要重复计算很多数字所以需要改进——记忆化搜索
开一个大数组记录中间的结果,如果算过了的话就查表,没算过就算一遍(递归层数太多容易爆栈)
#include<iostream>
using namespace std;
const int N = 1000000;
int a[N];
int f(int n){
if(a[n]) return a[n];
if(n==0) return 0;
if(n==1) return 1;
a[n] = f(n-1)+f(n-2);
return a[n];
}
int main(){
int n;
cin >> n;
cout << f(n);
return 0;
}
快速幂
#include<iostream>
using namespace std;
long long fastPower(long long base,long long power){
long long result = 1;
while(power > 0){
if(power%2 == 0){ //如果指数是偶数
power = power / 2; //指数减半
base = base * base; //底数平方
}
else{ //指数是奇数
power = power - 1; //指数减一
result = result * base; //结果把刚才减去的底数乘进去
power = power / 2; //减一变偶数了嘛跟上面一样
base = base * base;
}
}
return result;
}
int main(){
long long n,m;
cin >> n;
cin >> m;
cout << fastPower(n,m);
return 0;
}
对于上述代码我们还可以优化一下
power = power - 1;
power = power / 2;
这两句话我们能否做一下优化呢?
我们知道power是一个整数,当他是奇数的时候如5/2=2;和5-1=4,4/2=2结果一样,所以我们可以再优化一下代码。
#include<iostream>
using namespace std;
long long fastPower(long long base,long long power){
long long result = 1;
while(power > 0){
if(power%2 == 1) //如果是奇数
result = result * base; //结果先乘一下底数
power = power / 2; //指数除二
base = base * base; //底数平方
}
return result;
}
int main(){
long long n,m;
cin >> n;
cin >> m;
cout << fastPower(n,m);
return 0;
}
对于这个代码还有一个最最最终极的优化 这里运用到了位运算。
计算机中的所有数据都是以二进制的形式存储在设备中,即0、1两种状态,合理利用位运算可以更显著的提高代码的执行效率。
& | 与 | 两个位都为1时,结果才为1 |
---|---|---|
| | 或 | 两个位都为0时,结果才为0 |
^ | 异或 | 两个位相同为0,相异为1 |
~ | 取反 | 0变1,1变0 |
<< | 左移 | 各二进位全部左移若干位,高位丢弃,低位补0 |
>> | 右移 | 各二进位全部右移若干位,对无符号数,高位补0,有符号数编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移) |
power%2==1可以用更快的“位运算”来代替,例如:power&1。因为如果power为偶数,则其二进制表示的最后一位一定是0;如果power是奇数,则其二进制表示的最后一位一定是1。将他们分别与1的二进制做“与”运算,得到的就是power二进制最后一位的数字了,是0则为偶数,是1则为奇数。例如5是奇数,则5&1=1;而6是偶数,则6&1=0;因此奇偶数的判断就可以用“位运算”来替换了。
所以power=power/2;
可以用power>>1;
代替
long long fastPower(long long base, long long power) {
long long result = 1;
while (power > 0) {
if (power & 1) {//此处等价于if(power%2==1)
result = result * base ;
}
power >>= 1;//此处等价于power=power/2
base = base * base;
}
return result;
}
定义
#include <stdio.h>
#include <math.h>
int function( int i );
int main()
{
int N;
scanf( "%d", &N );
for ( int i = 1; i <= N - 1; i++ )
printf( "%d ", function( i ) );
printf( "%d", function( N ) );
return(0);
}
int function( int i )
{
double sqrt_five = sqrt( 5.0 );
double pow1 = pow( ( (1.0 + sqrt( 5.0 ) ) / 2.0), i );
double pow2 = pow( ( (1.0 - sqrt( 5.0 ) ) / 2.0), i );
int number = 1.0 / sqrt_five * (pow1 - pow2);
return(number);
}