题目:写一个函数,输入n,求斐波那契数列的第n项。斐波那契数列的定义如下:
思路:
① 可用直接将上述公式翻译成递归函数版本。但算法复杂度是指数级的,且不能写成尾递归的形式
② 可用循环迭代解决
思路:
① 可用直接将上述公式翻译成递归函数版本。但算法复杂度是指数级的,且不能写成尾递归的形式
② 可用循环迭代解决
编译环境:ArchLinux+Clang3.3,C++11
实现一:迭代版本。时间复杂度O(n)
#include <iostream>
#include <stdexcept>
using namespace std;
long long Fib(unsigned n)
{
if (n == 0)
return 0;
if (n == 1)
return 1;
long long fibN_1 = 1;
long long fibN_2 = 0;
long long fibN = 0;
for (int i = 2; i <= n; i++) {
fibN = fibN_1 + fibN_2; // 本次计算
/** 为下次迭代准备 **/
fibN_2 = fibN_1;
fibN_1 = fibN;
}
return fibN;
}
int main()
{
cout << Fib(0) << endl;
cout << Fib(1) << endl;
cout << Fib(2) << endl;
cout << Fib(3) << endl;
cout << Fib(4) << endl;
cout << Fib(5) << endl;
cout << Fib(6) << endl;
cout << Fib(7) << endl;
}
实现二:O(logn)解法(不实用)。常数因子大
使用如下公式:
实现代码如下(C99变长数组):对矩阵的n次方进行了优化
#include <stdlib.h>
#include <stdio.h>
/** 矩阵乘法:r = a*b **/
void matMult(int m, int k, int n, long long r[m][n], long long a[m][k], long long b[k][n]);
/** 复制矩阵:dst = src **/
void matCpy(int m, int n, long long dst[m][n], long long src[m][n]);
/** 计算Fib **/
long long Fib(unsigned n)
{
if (n == 0)
return 0;
if (n == 1)
return 1;
long long a[][2] = {{1,1},{1,0}};
long long r[][2] = {{1,1},{1,0}};
long long tmp[][2] = {{}, {}};
int m = 2;
unsigned mask = (1U << 31);
n -= 1;
while (!(mask&n)) { // 移动到二进制最高有效位
mask >>= 1;
}
mask >>= 1; // 循环初始状态
while (mask) {
matMult(m, m, m, tmp, r, r);
matCpy(m, m, r, tmp);
if (n & mask) { // 当前二进制位为1
matMult(m, m, m, tmp, r, a);
matCpy(m, m, r, tmp);
}
mask >>= 1;
}
return r[0][0];
}
void matMult(int m, int k, int n, long long r[m][n], long long a[m][k], long long b[k][n])
{
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
r[i][j] = 0;
for (int kk = 0; kk < k; kk++) {
r[i][j] += a[i][kk] * b[kk][j];
}
}
}
}
void matCpy(int m, int n, long long dst[m][n], long long src[m][n])
{
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
dst[i][j] = src[i][j];
}
}
}
int main()
{
printf("%lld\n", Fib(0));
printf("%lld\n", Fib(1));
printf("%lld\n", Fib(2));
printf("%lld\n", Fib(3));
printf("%lld\n", Fib(4));
printf("%lld\n", Fib(5));
printf("%lld\n", Fib(6));
printf("%lld\n", Fib(7));
}