C語言深入探究斐波那契數(shù)列
本文章參考leetcode斐波那契數(shù)官方題解
斐波那契的邊界條件是 F(0)=0 和 F(1)=1。當(dāng) n>1 時(shí),每一項(xiàng)的和都等于前兩項(xiàng)的和,因此有如下遞推關(guān)系:F(n)=F(n-1)+F(n-2)
一、遞歸思想
遞歸的思想是把一個大型復(fù)雜問題層層轉(zhuǎn)化為一個與原問題規(guī)模更小的問題,問題被拆解成子問題后,遞歸調(diào)用繼續(xù)進(jìn)行,直到子問題無需進(jìn)一步遞歸就可以解決的地步為止。
#include<stdio.h> int fib(int n) { return n > 2 ? n : fib(n - 1) + fib(n - 2); } int main() { int n; scanf("%d", &n); printf("%d\n", fib(n)); return 0; }
其時(shí)間復(fù)雜度為O(2^N),由于其時(shí)間復(fù)雜度太高,在實(shí)際應(yīng)用中用武之地并沒有想象的那么多,要是真寫個這種程序,老板應(yīng)該是不容下你了。
二、空間換時(shí)間
動態(tài)開辟空間將計(jì)算出的數(shù)據(jù)記錄下來,避免重復(fù)計(jì)算,使用空間換時(shí)間。
時(shí)間復(fù)雜度O(n),空間復(fù)雜度O(n)。
#include<stdio.h> #include<stdlib.h> long long fib(int n) { long long* p = (long long*)malloc(sizeof(long long) * (n+1)); p[0] = 0; p[1] = 1; for (int i = 2; i <= n; ++i) { p[i] = p[i - 1] + p[i - 2]; } long long temp = p[n]; free(p); p = NULL; return temp; } int main() { int n; scanf("%d", &n); printf("%lld\n", fib(n)); return 0; }
這里使用動態(tài)開辟空間而不用數(shù)組,因?yàn)閿?shù)組的大小有限制。
其缺點(diǎn)依然十分明顯,其空間復(fù)雜度較高,開辟堆區(qū)內(nèi)存,若管理不當(dāng),甚至可能造成內(nèi)存泄漏。(避免因未釋放堆區(qū)而造成內(nèi)存泄漏的小技巧:(7條消息) C++11智能指針的解析_GG_Bond18的博客-CSDN博客
https://blog.csdn.net/GG_Bruse/article/details/124136480)
三、動態(tài)規(guī)劃
本方法是在方法二的基礎(chǔ)上節(jié)省空間。利用滾動數(shù)組思想,將空間復(fù)雜度由O(n)優(yōu)化為O(1)。時(shí)間復(fù)雜度依然為O(n)。
#include<stdio.h> long long fib(int n) { if (n < 2) { return n; } long long left = 0, right = 1, ret = 1; for (int i = 2; i < n; ++i) { left = right; right = ret; ret = left + right; } return ret; } int main() { int n; scanf("%d", &n); printf("%lld\n", fib(n)); return 0; }
基本掌握這個方法就可以了。
四、通項(xiàng)公式
#include<stdio.h> #include<math.h> int fib(int n) { double sqrt5 = sqrt(5); double fibN = pow((1 + sqrt5) / 2, n) - pow((1 - sqrt5) / 2, n); return round(fibN / sqrt5); } int main() { int n; scanf("%d", &n); printf("%d\n", fib(n)); return 0; }
代碼中使用的pow函數(shù)的時(shí)空復(fù)雜度與 CPU 支持的指令集相關(guān),該文章不深入分析。
五、矩陣快速冪
#include<stdio.h> struct Matrix { int mat[2][2]; }; struct Matrix matrixMultiply(struct Matrix* a, struct Matrix* b) { struct Matrix c; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { c.mat[i][j] = (*a).mat[i][0] * (*b).mat[0][j] + (*a).mat[i][1] * (*b).mat[1][j]; } } return c; } struct Matrix matrixPow(struct Matrix a, int n) { struct Matrix ret; ret.mat[0][0] = ret.mat[1][1] = 1; ret.mat[0][1] = ret.mat[1][0] = 0; while (n > 0) { if (n & 1) { ret = matrixMultiply(&ret, &a); } n >>= 1; a = matrixMultiply(&a, &a); } return ret; } int fib(int n) { if (n < 2) { return n; } struct Matrix q; q.mat[0][0] = q.mat[0][1] = q.mat[1][0] = 1; q.mat[1][1] = 0; struct Matrix res = matrixPow(q, n - 1); return res.mat[0][0]; } int main() { int n; scanf("%d", &n); printf("%d", fib(n)); return 0; }
時(shí)間復(fù)雜度為O(logn),空間復(fù)雜度為O(1)。
六、總結(jié)
方法一和方法二盡量不要使用。
到此這篇關(guān)于C語言深入探究斐波那契數(shù)列的文章就介紹到這了,更多相關(guān)C語言斐波那契數(shù)列內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言實(shí)現(xiàn)可增容動態(tài)通訊錄詳細(xì)過程
這篇文章主要為大家介紹了C語言實(shí)現(xiàn)簡易通訊錄的完整流程,此通訊錄還可以增容,并且每個環(huán)節(jié)都有完整代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-05-05C++實(shí)現(xiàn)LeetCode(237.刪除鏈表的節(jié)點(diǎn))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(237.刪除鏈表的節(jié)點(diǎn)),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08基于C語言實(shí)現(xiàn)創(chuàng)意多彩貪吃蛇游戲
這篇文章主要介紹了如何利用C語言實(shí)現(xiàn)一個創(chuàng)意多彩貪吃蛇游戲,這是一個純C語言外加easyx庫的繪圖函數(shù)制作而成的有趣小游戲,無需引入額外資源,感興趣的可以動手嘗試一下2022-08-08Qt使用SQLite數(shù)據(jù)庫存儲管理圖片文件
這篇文章主要為大家詳細(xì)介紹了Qt如何使用SQLite數(shù)據(jù)庫實(shí)現(xiàn)存儲管理圖片文件的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-04-04