求斐波那契數列的三種方法------遞歸法、for循環法、快速冪矩陣法

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;
}

 

發佈了170 篇原創文章 · 獲贊 63 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章