網站首頁 編程語言 正文
《劍指offer》里講到了一種斐波那契數列的 O(logN) 時間復雜度的實現,覺得挺有意思的,三種方法都記錄一下。
一、遞歸
? ? 一般來說遞歸實現的代碼都要比循環要簡潔,但是效率不高,比如遞歸計算斐波那契數列第n個元素。
long long Fibonacci_Solution1(unsigned int n) { // printf("%d ", n); if (n <= 0) return 0; if (n == 1) return 1; return Fibonacci_Solution1(n - 1) + Fibonacci_Solution1(n - 2); }
? ? 如果計算數列的第4個位置上(從0開始)的數(0 1 1 2 3),也就是3,上邊的 printf 輸出應該是?4 3 2 1 0 1 2 1 0,這是因為計算 F(4) 要計算 F(3) 和 F(2),而計算 F(3) 的時候又要計算 F(2) 和 F(1),所以會有很多重復計算。用下圖可以更好地說明。
? ? 遞歸雖然有簡潔的優點,但它同時也有顯著地缺點。遞歸由于是函數調用自身,而函數調用是有空間和時間的消耗的:每一次函數調用,都需要在內存棧中分配空間以保存參數、返回地址及臨時變量,而且往棧里壓入數據和彈出數據都需要時間。
? ? 而且除了效率問題之外,遞歸可能引起 調用棧溢出,因為需要為每一次函數調用在內存棧中分配空間,而每個進程的棧的容量是有限的。當蒂固的層級太多,就會超出棧的容量,導致棧溢出。比如上邊的代碼,輸入40,可以正確返回 12502500,但是輸入 5000 就會出錯。
二、循環
? ? 最常規的正確做法就是用循環從小到大計算。
long long Fibonacci_Solution2(unsigned n) { if (n <= 1) return n; long long fib1 = 1, fib0 = 0, fibN = 0; for (unsigned int i = 2; i <= n; ++i) { fibN = fib1 + fib0; fib0 = fib1; fib1 = fibN; } return fibN; }
? ? 或者下邊這種
long long Fibonacci_Solution2(unsigned n) { if (n <= 1) return n; long long a = 0, b = 1; for (unsigned int i = 2; i <= n; ++i) { b = a + b; a = b - a; } return b; }
三、矩陣
? ? 數中提到了一種 O(logN) 時間復雜度的算法,就是利用數學公式計算。
? ? 首先需要知道下邊這個數學公式:
? ? ?這個公式用數學歸納法可以證明,所以只需要計算右邊矩陣的 n-1 次方就能得到 f(n),現在問題就變成了計算 2x2 矩陣的 n-1 次方,這樣做 n-2 次乘法就可以了,時間復雜度還是 O(N),但是還可以加速,如下式:
? ? ?所以我們可以看出,想求 n 次方可以求出 n / 2 次方再平方,所以時間復雜度可以將為 O(logN)。
struct Matrix2By2 { Matrix2By2(long long m00 = 0, long long m01 = 0, long long m10 = 0, long long m11 = 0) :m_00(m00), m_01(m01), m_10(m10), m_11(m11) {} long long m_00, m_01, m_10, m_11; }; Matrix2By2 MatrixMultiply(const Matrix2By2& matrix1, const Matrix2By2& matrix2) { return Matrix2By2( matrix1.m_00 * matrix2.m_00 + matrix1.m_01 * matrix2.m_10, matrix1.m_00 * matrix2.m_01 + matrix1.m_01 * matrix2.m_11, matrix1.m_10 * matrix2.m_00 + matrix1.m_11 * matrix2.m_10, matrix1.m_10 * matrix2.m_01 + matrix1.m_11 * matrix2.m_11 ); } Matrix2By2 MatrixPower(unsigned int n) { assert(n > 0); Matrix2By2 matrix; if (n == 1) matrix = Matrix2By2(1, 1, 1, 0); else if (n % 2 == 0) { // n是偶數 matrix = MatrixPower(n / 2); matrix = MatrixMultiply(matrix, matrix); } else if (n % 2 == 1) { // n是奇數 matrix = MatrixPower((n - 1) / 2); matrix = MatrixMultiply(matrix, matrix); matrix = MatrixMultiply(matrix, Matrix2By2(1, 1, 1, 0)); } return matrix; } long long Fibonacci_Solution3(unsigned int n) { if (n <= 1) return n; Matrix2By2 PowerNMinus2 = MatrixPower(n - 1); return PowerNMinus2.m_00; }
? ? 為了測試上邊三種方式的代碼的正確性,可以用如下樣例來測試。
// ====================測試代碼==================== void Test(int n, int expected) { if (Fibonacci_Solution1(n) == expected) printf("Test for %d in solution1 passed.\n", n); else printf("Test for %d in solution1 failed.\n", n); if (Fibonacci_Solution2(n) == expected) printf("Test for %d in solution2 passed.\n", n); else printf("Test for %d in solution2 failed.\n", n); if (Fibonacci_Solution3(n) == expected) printf("Test for %d in solution3 passed.\n", n); else printf("Test for %d in solution3 failed.\n", n); } int main(int argc, char* argv[]) { Test(0, 0); Test(1, 1); Test(2, 1); Test(3, 2); Test(4, 3); Test(5, 5); Test(6, 8); Test(7, 13); Test(8, 21); Test(9, 34); Test(10, 55); Test(40, 102334155); return 0; }
原文鏈接:https://blog.csdn.net/Bob__yuan/article/details/84956740
相關推薦
- 2022-07-20 Python3.7.2環境安裝
- 2022-03-25 在NET?Core?中獲取?CPU?使用率_ASP.NET
- 2022-04-03 Docker?部署RocketMQ的詳細操作_docker
- 2022-05-28 Python庫AutoTS一行代碼得到最強時序基線_python
- 2022-07-03 對比分析BN和dropout在預測和訓練時區別_python
- 2022-09-30 關于react中useCallback的用法_React
- 2022-12-10 MongoDB中的push操作詳解(將文檔插入到數組)_MongoDB
- 2022-10-09 python將寫好的程序打包成exe可執行文件_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支