1 遞歸法求斐波那契數列,時間複雜度O(n^2),實現代碼如下:
#include <iostream>
using namespace std;
int Fib(int n) {
if(n <= 2) return 1;
else {
return Fib(n-1) + Fib(n-2);
}
}
int main(){
int n, result;
cin >> n;
result = Fib(n);
cout << result;
return 0;
}
2 for循環法求斐波那契數列,時間複雜度O(n), 其實改進的方法並不複雜。
上述遞歸代碼之所以慢是因爲重複的計算太多,我們只要想辦法避免重複計算就行了。比如我們可以把已經得到的數列中間項保存起來,如果下次需要計算的時候我們先查找一下,如果前面已經計算過就不用再重複計算了。 更簡單的辦法是從下往上計算,首先根據f(0)和f(1)算出f(2),再根據f(1)和f(2)算出f.(....依此類推就可以算出第n項了。很容易理解,這種.思路的時間複雜度是0(n)。實現代碼如下:
#include <iostream>
using namespace std;
long long Fib(int n) {
int result[2] = {0, 1};
if(n < 2) {
return result[n];
}
long long fibone = 1;
long long fibtwo = 0;
long long fibN = 0;
for(int i = 2; i <= n; i++) {
fibN = fibone + fibtwo;
fibtwo = fibone;
fibone = fibN;
}
return fibN;
}
int main(){
long long n;
cin >> n;
cout << "第" << n << "項的斐波那契數爲: " << Fib(n);
return 0;
}
3 快速冪法求斐波那契數列,時間複雜度O(logN)
(1)爲什麼要用快速冪?
例如:現在有一個題目讓你求 ,你可能覺得很簡單啊,來一個for
循環,循環b-1
次就行了。但是如果b非常大的情況下,那這個做法是非常低效的,時間複雜度大致爲 O(b)
。
當用快速冪之後,時間複雜度爲O(logn)
。
(2)數的快速冪
例如我們用快速冪求 。
將指數拆分能夠得到如下的結果。
學過進制轉換看到11拆開的樣子肯定會很眼熟,其實這裏就是跟二進制有關。
11的二進制爲1011
,我們只需要把11的二進制代碼中爲1的位數對應的2^n累乘起來即可,如2^11=2^8*2^2*2,對應二進制數中的第0、1、3位(從右往左數)均爲1,故把它們累乘起來即可得到2^11。
這樣一來,我們求2^11就不需要算10次了,現在三次就夠了。
實現代碼如下:
// 利用快速冪求x^n
#include <iostream>
using namespace std;
int pow(int x, int n) {
int ans = 1, base = x; //base 爲底數, ans爲最後累乘的結果x^n
while(n != 0) {
if(n&1 != 0) {
ans *= base;
}
base *= base;
n >>= 1; // 等價於把n右移一位並吧結果賦給n
}
return ans;
}
int main(){
int x, n;
cout << "請輸入底數:";
cin >> x;
cout << endl;
cout << "請輸入指數:";
cin >> n;
cout << x << "^" << n << "=" << pow(x, n);
return 0;
}
(3)矩陣的快速冪
於是我們得到如下公式: 其中Fn則對應結果矩陣result[0][1]的值
利用矩陣的快速冪書寫如下代碼:
//用矩陣快速冪求斐波那契數列
#include <iostream>
#include<cstring>
using namespace std;
struct Matrix { //定義矩陣結構體
int a[2][2];
};
Matrix muliMatrix(Matrix x, Matrix y) { //求兩個矩陣相乘
Matrix result; //結果矩陣result
memset(result.a, 0, sizeof(result.a)); //將結果矩陣的元素全部初始化爲0
for(int i = 0; i < 2; i++) {
for(int j = 0; j < 2; j++) {
for(int k = 0; k < 2; k++){
result.a[i][j] += x.a[i][k] * y.a[k][j]; //矩陣的乘法
}
}
}
return result;
}
int matrixPow(int n) { //快速冪求斐波那契數列
Matrix res, c;
memset(res.a, 0, sizeof(res.a));
for(int i = 0; i < 2; i++) {
res.a[i][i] = 1; //將res初始化爲單位矩陣,因爲任何矩陣和單位矩陣相乘都是它本身
}
c.a[0][0] = 1; //構造斐波那契矩陣
c.a[0][1] = 1;
c.a[1][0] = 1;
c.a[1][1] = 0;
while(n) {
if(n&1 != 0){ //這裏和求x^n的快速冪類似
res = muliMatrix(res, c);
}
c = muliMatrix(c, c);
n >>= 1; // 等價於把n右移一位並把結果賦給n即n=>>1
}
return res.a[0][1]; //由於斐波那契第n項Fn對應結果舉證中res.a[0][1]的值
}
int main(){
int n;
cout << "請輸入斐波那契數列的項數: ";
cin >> n;
cout << endl;
cout << "第" << n << "項斐波那契數列的值=" << matrixPow(n);
return 0;
}