计算机考研之数据结构:斐波那契数列专题(2)

《计算机考研之数据结构:斐波那契数列专题(1)》中分析用递归方式描述的斐波那契数列的时间复杂度,还计算了斐波那契数列的通项。从而得知,如果用递归方式实现(如下代码):

复制代码
long fib(long n){
    if(n == 1 || n == 2) return 1;
    else return fib(n-1) + fib(n-2);
}

其时间复杂度为指数级,不是一个有价值的算法。

实现斐波那契数列,通常作为我这里的一道面试题,多数来面试的给出的都是上面那个"没有价值"的实现方法。

对于斐波那契数列的实现,除了递归(最不提倡的)之外,还有其他方法。

1. 斐波那契数列的实现方法

以下用 Python 语言描述。

1.1 递归

python 复制代码
# 递归
def fib_recu(n):
    if n <= 1:
        return n
    else:
        return fib_recu(n-1) + fib_recu(n-2)

print("fibonacci number:")
for i in range(10):
    print(f"{fib_recu(i)}", end=" ")
    
# 输出:
fibonacci number:
0 1 1 2 3 5 8 13 21 34 

递归方法,思路简单,但是"没有价值"。

1.2 循环

python 复制代码
def fib_loop(n):
    fibs = [0, 1]
    if n <= 1:
        return n
    else:
        for i in range(n-2):
            fibs.append(fibs[-2] + fibs[-1])
    return fibs

print(f"fibonacci number: {fib_loop(10)}")

# 输出:
fibonacci number: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

循环方法,也称为递推法,即递增。随着数量的增大,执行速度会越来越慢。

1.3 迭代器对象

python 复制代码
class Fibs:
    def __init__(self, max):
        self.max = max
        self.a = 0
        self.b = 1

    def __iter__(self):
        return self

    def __next__(self):
        fib = self.a
        if fib > self.max:
            raise StopIteration
        self.a, self.b = self.b, self.a + self.b
        return fib

fibs = Fibs(100000)
lst = [ fibs.__next__() for i in range(10)]
print(lst)

# 输出
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

1.4 生成器对象

python 复制代码
def fibs():
    prev, curr = 0, 1
    while True:
        yield prev
        prev, curr = curr, prev + curr


import itertools
print(list(itertools.islice(fibs(), 10)))

# 输出
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

通过fibs()得到了含有无限项斐波那契数的对象,只不过在上面只向内存中读入了10个。

1.5 矩阵

本方法来自《跟老齐学Python:数据分析》(电子工业出版社)

python 复制代码
import numpy as np
def fib_matrix(n):
    F = np.mat([[1,1], [1,0]])
    F_m = pow(F, n)
    return F_m[0, 0]

print("fibonacci numbers:")
for i in range(10):
    print(fib_matrix(i), end=" ")
    
# 输出
fibonacci numbers:
1 1 2 3 5 8 13 21 34 55

2. 黄金分割

对斐波那契数列还可以做进一步的研究,以下纯属个人爱好。

如果用斐波那契数列中的后面的数字除以前面的数字,结果会如何?

python 复制代码
def fib_iter():
    prev, curr = 0, 1
    while True:
        yield prev
        prev, curr = curr, prev + curr

import itertools
fibs = list(itertools.islice(fib_iter(), 100))
for i in range(2, 30):
    print(f"{fibs[i+1]}/{fibs[i]}={fibs[i+1]/fibs[i]}")
    
# 输出
2/1=2.0
3/2=1.5
5/3=1.6666666666666667
8/5=1.6
13/8=1.625
21/13=1.6153846153846154
34/21=1.619047619047619
55/34=1.6176470588235294
89/55=1.6181818181818182
144/89=1.6179775280898876
233/144=1.6180555555555556
377/233=1.6180257510729614
610/377=1.6180371352785146
987/610=1.618032786885246
1597/987=1.618034447821682
2584/1597=1.6180338134001253
4181/2584=1.618034055727554
6765/4181=1.6180339631667064
10946/6765=1.6180339985218033
17711/10946=1.618033985017358
28657/17711=1.6180339901755971
46368/28657=1.618033988205325
75025/46368=1.618033988957902
121393/75025=1.6180339886704431
196418/121393=1.6180339887802426
317811/196418=1.618033988738303
514229/317811=1.6180339887543225
832040/514229=1.6180339887482036

从上面的输出结果发现: f n + 1 f n ≈ 1.618 ⋯ \frac{f_{n+1}}{f_n}\approx 1.618\cdots fnfn+1≈1.618⋯

这就是我们熟悉的黄金分割------黄金比例,准确值是 φ = 1 + 5 2 \varphi = \frac{1+\sqrt{5}}{2} φ=21+5 ,这是一个无理数,小数点后20位的近似值是: φ = 1.61803398874989484820 \varphi=1.61803398874989484820 φ=1.61803398874989484820 ,一般取 1.618 1.618 1.618 即可。

在历史上,伟大的天文学家开普勒,最早发现了这个结论。

《计算机考研之数据结构:斐波那契数列专题(1)》已经计算得到了斐波那契数列通项表达式:

F k = 1 5 [ ( 1 + 5 2 ) k − ( 1 − 5 2 ) k ] , ( k = 0 , 1 , 2 , ⋯   ) F_k=\frac{1}{\sqrt{5}}\left[\left(\frac{1+\sqrt{5}}{2}\right)^{k}-\left(\frac{1-\sqrt{5}}{2}\right)^{k}\right] ,(k=0,1,2,\cdots) Fk=5 1 (21+5 )k−(21−5 )k ,(k=0,1,2,⋯)

将此结论对照上述结算结果,亦得有趣结果。

3. 斐波那契数列的有关性质

结合之前得到的斐波那契数列通项表达式,可知如下有关性质。

性质1: lim ⁡ k → ∞ F k + 1 F k = 1 + 5 2 \lim_{k\to\infty}\frac{F_{k+1}}{F_k}=\frac{1+\sqrt{5}}{2} limk→∞FkFk+1=21+5

证明

对于 k ≥ 1 k\ge 1 k≥1 ,由(12)式得:

lim ⁡ k → ∞ F k + 1 F k = lim ⁡ k → ∞ ( 1 + 5 ) k + 1 − ( 1 − 5 ) k + 1 2 k + 1 5 ⋅ 2 k 5 ( 1 + 5 ) k − ( 1 − 5 ) k = 1 2 lim ⁡ k → ∞ ( 1 + 5 ) k + 1 − ( 1 − 5 ) k + 1 ( 1 + 5 ) k − ( 1 − 5 ) k = 1 2 lim ⁡ k → ∞ ( 1 + 5 ) − ( 1 − 5 1 + 5 ) k ( 1 − 5 ) 1 − ( 1 − 5 1 + 5 ) k = 1 + 5 2 \begin{split}\lim_{k\to\infty}\frac{F_{k+1}}{F_k}&=\lim_{k\to\infty}\frac{(1+\sqrt{5})^{k+1}-(1-\sqrt{5})^{k+1}}{2^{k+1}\sqrt{5}}\cdot\frac{2^k\sqrt{5}}{(1+\sqrt{5})^{k}-(1-\sqrt{5})^{k}}\\&=\frac{1}{2}\lim_{k\to\infty}\frac{(1+\sqrt{5})^{k+1}-(1-\sqrt{5})^{k+1}}{(1+\sqrt{5})^{k}-(1-\sqrt{5})^{k}}\\&=\frac{1}{2}\lim_{k\to\infty}\frac{(1+\sqrt{5})-\left(\frac{1-\sqrt{5}}{1+\sqrt{5}}\right)^k(1-\sqrt{5})}{1-\left(\frac{1-\sqrt{5}}{1+\sqrt{5}}\right)^k}\\&=\frac{1+\sqrt{5}}{2}\end{split} k→∞limFkFk+1=k→∞lim2k+15 (1+5 )k+1−(1−5 )k+1⋅(1+5 )k−(1−5 )k2k5 =21k→∞lim(1+5 )k−(1−5 )k(1+5 )k+1−(1−5 )k+1=21k→∞lim1−(1+5 1−5 )k(1+5 )−(1+5 1−5 )k(1−5 )=21+5

( ∵ ∣ 1 − 5 1 + 5 ∣ < 1 , lim ⁡ k → ∞ ( 1 − 5 1 + 5 ) k = 0 \because \quad \begin{vmatrix}\frac{1-\sqrt{5}}{1+\sqrt{5}}\end{vmatrix}\lt 1, \quad \lim_{k\to\infty}\left(\frac{1-\sqrt{5}}{1+\sqrt{5}}\right)^k=0 ∵ 1+5 1−5 <1,limk→∞(1+5 1−5 )k=0 )

证毕。

所以,在前面的程序中,显示后项除以前项的结果趋近于黄金分割。

性质2: 幂矩阵 A k \pmb{A}^k Ak

因为 A = [ 1 1 1 0 ] \pmb{A}=\begin{bmatrix}1&1\\1&0\end{bmatrix} A=[1110] ,又因为斐波那契数列 F 0 = 0 , F 1 = 1 , F 2 = 1 F_0=0,F_1=1,F_2=1 F0=0,F1=1,F2=1 ,所以:

A = [ 1 1 1 0 ] = [ F 2 F 1 F 1 F 0 ] \pmb{A}=\begin{bmatrix}1&1\\1&0\end{bmatrix}=\begin{bmatrix}F_2&F_1\\F_1&F_0\end{bmatrix} A=[1110]=[F2F1F1F0]

A 2 = [ 1 1 1 0 ] [ F 2 F 1 F 1 F 0 ] = [ F 2 + F 1 F 1 + F 0 F 2 F 1 ] = [ F 3 F 2 F 2 F 1 ] \pmb{A}^2=\begin{bmatrix}1&1\\1&0\end{bmatrix}\begin{bmatrix}F_2&F_1\\F_1&F_0\end{bmatrix}=\begin{bmatrix}F_2+F_1&F_1+F_0\\F_2&F_1\end{bmatrix}=\begin{bmatrix}F_3&F_2\\F_2&F_1\end{bmatrix} A2=[1110][F2F1F1F0]=[F2+F1F2F1+F0F1]=[F3F2F2F1]

以此类推,可得:

A k = [ F k + 1 F k F k F k − 1 ] (1) \pmb{A}^k=\begin{bmatrix}F_{k+1}&F_k\\F_k&F_{k-1}\end{bmatrix}\tag{1} Ak=[Fk+1FkFkFk−1](1)

其中 A = [ 1 1 1 0 ] \pmb{A}=\begin{bmatrix}1&1\\1&0\end{bmatrix} A=[1110]

这就是矩阵法计算斐波那契数列的程序编写依据。

性质3: Cassini 等式

《机器学习数学基础》第2章2.4节中曾经介绍过行列式的性质,下面应用其中一条: ∣ A B ∣ = ∣ A ∣ ∣ B ∣ |\pmb{AB}|=|\pmb{A}||\pmb{B}| ∣AB∣=∣A∣∣B∣ 。

由(1)可得:

∣ A k ∣ = ∣ F k + 1 F k F k F k − 1 ∣ = F k + 1 F k − 1 − F n 2 |\pmb{A}^k|=\begin{vmatrix}F_{k+1}&F_k\\F_k&F_{k-1}\end{vmatrix}=F_{k+1}F_{k-1}-F_n^2 ∣Ak∣= Fk+1FkFkFk−1 =Fk+1Fk−1−Fn2

又因为:

∣ A k ∣ = ∣ A ∣ k = ∣ 1 1 1 0 ∣ k = ( − 1 ) k |\pmb{A}^k|=|\pmb{A}|^k=\begin{vmatrix}1&1\\1&0\end{vmatrix}^k=(-1)^k ∣Ak∣=∣A∣k= 1110 k=(−1)k

所以:

F k + 1 F k − 1 − F n 2 = ( − 1 ) k (2) F_{k+1}F_{k-1}-F_n^2=(-1)^k\tag{2} Fk+1Fk−1−Fn2=(−1)k(2)

(2)式即为 Cassini 等式。表明了斐波那契数列的数之间的一种关系。如:

2 × 5 − 3 2 = 1 3 × 8 − 5 2 = − 1 5 × 13 − 8 2 = 1 8 × 21 − 1 3 2 = − 1 \begin{split}2\times5-3^2&=1\\3\times8-5^2&=-1\\5\times13-8^2&=1\\8\times21-13^2&=-1\end{split} 2×5−323×8−525×13−828×21−132=1=−1=1=−1

性质4: 前 n n n 项的和

设 F k F_k Fk 为斐波那契数列中的第 k k k 项,则:

F k + 2 = F k + 1 + F k , ( k = 0 , 1 , 2 , ⋯   ) F_{k+2} = F_{k+1} + F_k,(k=0,1,2,\cdots) Fk+2=Fk+1+Fk,(k=0,1,2,⋯)

根据斐波那契数列的特点,设定初始条件: F 0 = 0 , F 1 = 1 F_0=0, F_1=1 F0=0,F1=1 。

由此得:

F n = F n + 2 − F n + 1 F n − 1 = F n + 1 − F n F n − 2 = F n − F n − 1 ⋮ F 2 = F 4 − F 3 F 1 = F 3 − F 2 \begin{split}F_n &= F_{n+2}-F_{n+1}\\F_{n-1}&=F_{n+1}-F_n\\F_{n-2}&=F_{n}-F_{n-1}\\&\vdots\\F_2&=F_4-F_3\\F_1&=F_3-F_2\end{split} FnFn−1Fn−2F2F1=Fn+2−Fn+1=Fn+1−Fn=Fn−Fn−1⋮=F4−F3=F3−F2

上面各式等号左右各自相加,得:

F 1 + ⋯ + F n = ( F 3 + ⋯ + F n + 1 + F n + 2 ) − ( F 2 + F 3 + ⋯ + F n + 1 ) = F n + 2 − F 2 F_1+\cdots+F_n=(F_3+\cdots+F_{n+1}+F_{n+2})-(F_2+F_3+\cdots+F_{n+1})=F_{n+2}-F_2 F1+⋯+Fn=(F3+⋯+Fn+1+Fn+2)−(F2+F3+⋯+Fn+1)=Fn+2−F2

因为 F 2 = 1 F_{2}=1 F2=1 ,所以,前 n n n 项的和是:

∑ i = 1 n F i = F n + 2 − 1 (3) \sum_{i=1}^nF_i=F_{n+2}-1\tag{3} i=1∑nFi=Fn+2−1(3)

性质5: 每项的平方和
F n F n + 1 = F n ( F n + F n − 1 ) = F n 2 + F n − 1 F n = F n 2 + F n − 1 ( F n − 1 + F n − 2 ) = F n 2 + F n − 1 2 + F n − 2 F n − 1 = ⋯ = F n 2 + F n − 1 2 + ⋯ + F 2 2 + F 2 F 1 \begin{split}F_nF_{n+1}&=F_n(F_n+F_{n-1})\\&=F^2_n+F_{n-1}F_n\\&=F_n^2+F_{n-1}(F_{n-1}+F_{n-2})\\&=F_n^2+F_{n-1}^2+F_{n-2}F_{n-1}\\&=\cdots\\&=F_n^2+F_{n-1}^2+\cdots+F_2^2+F_2F_1\end{split} FnFn+1=Fn(Fn+Fn−1)=Fn2+Fn−1Fn=Fn2+Fn−1(Fn−1+Fn−2)=Fn2+Fn−12+Fn−2Fn−1=⋯=Fn2+Fn−12+⋯+F22+F2F1

又因为: F 2 = F 1 = 1 F_2=F_1=1 F2=F1=1 ,所以:

∑ i = 1 n F i 2 = F n F n + 1 (4) \sum_{i=1}^nF_i^2=F_nF_{n+1} \tag{4} i=1∑nFi2=FnFn+1(4)

相关推荐
柃歌3 小时前
【LeetCode Solutions】LeetCode 136 ~ 140 题解
数据结构·算法·leetcode
杰瑞学AI4 小时前
LeetCode详解之如何一步步优化到最佳解法:21. 合并两个有序链表
数据结构·python·算法·leetcode·链表·面试·职场和发展
WG_175 小时前
图的储存+图的遍历
数据结构·算法
MPCTHU5 小时前
线性方程组的解法
数据结构·算法
m0_540507789 小时前
2026考研数学张宇武忠祥复习视频课,高数基础班+讲义PDF
考研·pdf
技术小白Byteman9 小时前
蓝桥刷题note13(排序)
开发语言·数据结构·c++·学习·算法·visualstudio
_星辰大海乀9 小时前
二叉树相关练习--2
java·开发语言·数据结构·算法·链表·idea
梭七y9 小时前
【力扣hot100题】(064)在排序数组中查找元素的第一个和最后一个位置
数据结构·算法·leetcode
Protein_zmm11 小时前
[数据结构]图krusakl算法实现
数据结构·算法
勤劳的进取家11 小时前
贪心算法的使用条件
数据结构·python·算法·贪心算法·排序算法·动态规划