——————————————————————————————
这个题目大家很熟悉,就是Fibonacci数列,大家第一个想到的就是递归方法,是的,这个我们学数据结构算法的时候用的就是这个方法,代码精简漂亮,可是有没有想过时间和空间上的开销呢?首先这是一个递归,空间上开销不用说,栈会不断积累,时间,当我们计算F(n-1)时候计算了F(n-2),可是递归没有记忆功能,所以计算F(n-2)还是在来一次,这就造成了时间复杂度的上升应该是O(n2)
(1)循环
所以这里稍微改进下,首先,递归一般都可以采用非递归方式实现,这里我们用循环来实现
long Fibonacci1(long input){ long a0 = 1; long a1 = 1; long sum = 0; int i = 0; if(input <2) return 1; for(i=2;i<=input;i++){ sum = a0+a1; a0 = a1; a1 = sum; } return sum; }
后来我上网搜了下大家对这道题的看法,有人提出了更巧妙的方式,循环的时间复杂度我们知道就是O(N)似乎已经很好了,不过还有O(logN)的方法
(2)矩阵
大家可以计算下
| 1 1 |
| 1 0 |
这个矩阵的n次方的规律,我们发现,刚好就是
|f(n-1)+f(n-2) f(n-1) |
|f(n-1) f(n-2) |
所以这道题就可以转换成矩阵求幂了。
可以A^n还是需要计算n次啊,我们可以利用平方的性质 [A^(n/2)}^2 = A^n 所以以此类推 那就是logN的复杂度了 不过要注意奇数偶数的幂
偶数 A^n = [A^(n/2)}^2
奇数 A^n = [A^((n-1)/2)}^2*{1,1,1,0}
long Fibonacci3(int input){ long arr[4] = {1,1,1,0}; long* result = F3(arr, input); return result[0]; } long* F3(long* arr, int input){ long arr1[4], arr2[4]; long* temp1 = arr1; long* temp2 = arr2; if(input == 1){ temp1[0] = 1; temp1[1] = 1; temp1[2] = 1; temp1[3] = 0; return temp1; } if(input == 2){//求得平方 temp1[0] = arr[0]*arr[0] + arr[1]*arr[2]; temp1[1] = arr[0]*arr[1] + arr[1]*arr[3]; temp1[2] = arr[2]*arr[0] + arr[3]*arr[2]; temp1[3] = arr[2]*arr[1] + arr[3]*arr[3]; return temp1; }else{ if(input%2 == 0){ temp1 = F3(arr, input/2); temp2[0] = temp1[0]*temp1[0] + temp1[1]*temp1[2]; temp2[1] = temp1[0]*temp1[1] + temp1[1]*temp1[3]; temp2[2] = temp1[2]*temp1[0] + temp1[3]*temp1[2]; temp2[3] = temp1[2]*temp1[1] + temp1[3]*temp1[3]; return temp2; }else{ temp1 = F3(arr, (input-1)/2); temp2[0] = temp1[0]*temp1[0] + temp1[1]*temp1[2]; temp2[1] = temp1[0]*temp1[1] + temp1[1]*temp1[3]; temp2[2] = temp1[2]*temp1[0] + temp1[3]*temp1[2]; temp2[3] = temp1[2]*temp1[1] + temp1[3]*temp1[3]; temp1[0] = temp2[0] + temp2[1]; temp1[1] = temp2[0] ; temp1[2] = temp2[2] + temp2[3]; temp1[3] = temp2[2] ; return temp1; } } cout<<"NULL??"; return NULL; }
参见:http://blog.csdn.net/yuucyf/article/details/6625301
(3)递归
为了比较,这里还是把老式方法给出来
long Fibonacci2(long input){ if(input < 2) return 1; else return Fibonacci2(input-1)+Fibonacci2(input-2); }
我这里为了不让数列数太大,我循环执行,为了比较效率
long Fibonacci1(long input); long Fibonacci2(long input); long Fibonacci3(int input); long* F3(long* arr, int input); int main() { long input = 0l; cin>>input; int i =0; long result; clock_t start,end; //循环方法 cout<<endl<<"循环:"<<endl; start = clock(); for(i=0;i<3000000;i++) result = Fibonacci1(input); cout<<result; end = clock(); cout<<endl<<(double)(end-start)/CLOCKS_PER_SEC; //老式递归 cout<<endl<<"递归:"<<endl; start = clock(); for(i=0;i<3000000;i++) result = Fibonacci2(input); cout<<result; end = clock(); cout<<endl<<(double)(end-start)/CLOCKS_PER_SEC; //举证方法 cout<<endl<<"矩阵:"<<endl; start = clock(); for(i=0;i<3000000;i++) result = Fibonacci3(input); cout<<result; end = clock(); cout<<endl<<(double)(end-start)/CLOCKS_PER_SEC; return 0; }
输出比较
13 循环: 377 0.18s 递归: 377 9.68s 矩阵: 377 0.26s我们看到,老式的递归将近10秒了,由于输入10较小所以矩阵的速度无法充分体现出来,这里递归影响较大
我们看到,当输入求50的时候,时间就差开啦
50 循环: 20365011074 0.71s 矩阵: 20365011074 0.38s