递推 = 状态 + 转移。理解了斐波那契,你就理解了动态规划的骨架。
四种实现:从 O(2ⁿ) 到 O(log n)
package main
import "fmt"
// 1. 朴素递归:O(2^n),F(50) 需要计算 2^50 次
func fibNaive(n int) int {
if n <= 1 { return n }
return fibNaive(n-1) + fibNaive(n-2)
}
// 2. 记忆化递归:O(n)
func fibMemo(n int, memo map[int]int) int {
if n <= 1 { return n }
if v, ok := memo[n]; ok { return v }
memo[n] = fibMemo(n-1, memo) + fibMemo(n-2, memo)
return memo[n]
}
// 3. 迭代 DP:O(n) 时间,O(1) 空间
func fibDP(n int) int {
if n <= 1 { return n }
a, b := 0, 1
for i := 2; i <= n; i++ {
a, b = b, a+b
}
return b
}
// 4. 矩阵快速幂:O(log n)
// [F(n+1)] [1 1]^n [F(1)]
// [F(n) ] = [1 0] × [F(0)]
type mat [2][2]int
func matMul(a, b mat) mat {
var c mat
for i := 0; i < 2; i++ {
for j := 0; j < 2; j++ {
for k := 0; k < 2; k++ {
c[i][j] += a[i][k] * b[k][j]
}
}
}
return c
}
func matPow(m mat, n int) mat {
result := mat{{1, 0}, {0, 1}} // 单位矩阵
for n > 0 {
if n&1 == 1 { result = matMul(result, m) }
m = matMul(m, m)
n >>= 1
}
return result
}
func fibMatrix(n int) int {
if n <= 1 { return n }
base := mat{{1, 1}, {1, 0}}
return matPow(base, n)[0][1]
}
func main() {
fmt.Println(fibDP(10)) // 55
fmt.Println(fibMatrix(10)) // 55
fmt.Println(fibMatrix(50)) // 12586269025
}
黄金比例与增长率
斐波那契数列的相邻比 F(n+1)/F(n) 趋近于黄金比例 φ = (1+√5)/2 ≈ 1.618。这可以用特征方程求解:x² = x + 1,解为 φ = (1+√5)/2 和 ψ = (1-√5)/2,通项公式为 F(n) = (φⁿ - ψⁿ) / √5。这个公式揭示了斐波那契数列指数增长的本质。
package main
import (
"fmt"
"math"
)
func main() {
phi := (1 + math.Sqrt(5)) / 2
psi := (1 - math.Sqrt(5)) / 2
// Binet 公式(浮点近似,大 n 会有误差)
binetFib := func(n int) int {
return int(math.Round((math.Pow(phi, float64(n)) - math.Pow(psi, float64(n))) / math.Sqrt(5)))
}
for i := 0; i <= 10; i++ {
fmt.Printf("F(%2d) = %d\n", i, binetFib(i))
}
// 相邻比趋近黄金比例
a, b := 1, 1
for i := 0; i < 10; i++ {
fmt.Printf("%.6f ", float64(b)/float64(a))
a, b = b, a+b
}
fmt.Println() // 1.618... 越来越精确
}
递推数列的通用框架
所有线性常系数递推都可以用矩阵快速幂加速到 O(log n)。爬楼梯问题、Tribonacci、任意 k 阶线性递推,都套同一个框架:写出转移矩阵,用矩阵快速幂求第 n 个状态向量。
✓推荐做法
- 写递推时先想「状态是什么」再写转移方程
- 记忆化是把递归树剪掉重复子树的通用技巧
- 大 n 的线性递推用矩阵快速幂
✗不推荐
- 直接用 Binet 公式——浮点误差在 n>70 时显现
- 对每个递推问题都直接上矩阵——先写 O(n) DP,确认正确后再优化
⚠常见误区
- 矩阵乘法是 O(k³) 的,k 阶线性递推的矩阵快速幂是 O(k³ log n)
判断标准:能写出斐波那契的转移矩阵并解释为什么矩阵快速幂是 O(log n) → 掌握本章。
斐波那契数列是数学里最美的意外——它从兔子繁殖开始,却贯穿了整个现代算法。
— 具体数学