遞迴與動態規劃---斐波那契系列問題的遞迴,動態規劃與矩陣乘法
【題目】
- 給定整數N,返回斐波那契數列的第N項
- 假設農場中成熟的母牛每年只會生一頭小母牛,並且永遠不會死。第一年農場有1只成熟的牛,從第二年開始,母牛開始生小母牛。每隻小母牛3年之後 成熟又可以生小母牛。給定整數N,返回N年後牛的數量。
【基本思路】
原問題。O(2^N)的方法。斐波那契數列為1,1,2,3,5,8……,也就是除第一項和第二項以外,對於第N項,有F(N) = F(N-1) + f(N-2),於是可以很輕鬆的寫出暴力遞迴的程式碼。下面是使用python3.5實現的程式碼:
遞迴。時間複雜度(2^N)
def fibonacci1(n):
if n < 1:
return 0
if n == 1 or n == 2:
return 1
return fibonacci1(n-1) + fibonacci1(n-2)
O(N)的方法。斐波那契可以從左到右依次求出每一項的值,那麼可以順序計算求到第N項即可。下面是使用python3.5實現的程式碼:
遞迴。時間複雜度(2^N)
def fibonacci2(n):
if n < 1:
return 0
if n == 1 or n == 2:
return 1
pre = 1
cur = 1
for i in range(3, n+1):
tmp = cur
cur = pre + cur
pre = tmp
return cur
O(logN)的方法。矩陣乘法推導如下(字醜見諒)
所以現在的問題就變成了如何使用最快的方法求一個矩陣的N次方,而求一個矩陣的N次方明顯可以在O(logN)時間內完成。為了表述方便,現在使用一個整數N次方的例子來說明,矩陣的求解過程類似。
假設一個整數是10,如何快速的求解10的75次方。
75的二進位制形式為1001011.
10的75次方 =
10
在這個過程中,我們先求出101 ,然後根據101 求出102 ,再根據102 求出104 ,……,最後再根據1032 求出1064 ,即75的二進位制形式總共有多少位,我們就使用幾次乘法。在步驟2進行的過程中,把應該累乘的值相乘即可。即二進位制形式中是1的位置的相乘,這樣就得到結果
1064∗108∗102∗101 。
下面是使用python3.5實現的程式碼:
#矩陣乘法方法。時間複雜度(logN)
def fibonacciUseMatrix(n):
def matrixPower(m, p):
res = [[0 if i != j else 1 for i in range(len(m[0]))] for j in range(len(m))] #單位矩陣
tmp = m
while p > 0:
if p & 1 != 0:
res = muliMatrix(res, tmp)
tmp = muliMatrix(tmp, tmp)
p >>= 1
return res
def muliMatrix(m1, m2):
res = [[0 for i in range(len(m2[0]))] for j in range(len(m1))]
for i in range(len(m1)):
for j in range(len(m2[0])):
for k in range(len(m1[0])):
res[i][j] += m1[i][k] * m2[k][j]
return res
if n < 1:
return 0
if n == 1 or n == 2:
return 1
base = [[1,1],[1,0]]
res = matrixPower(base, n-2)
return res[0][0] + res[0][1]
母牛數量問題。所有牛都不會死,所以第N-1年的牛都會活到第N年。同時,所有成熟的母牛都會生一隻小母牛,那麼成熟牛的數量怎麼計算呢?就是第N-3年的所有牛,到第N年肯定都是成熟的牛,期間出生的牛肯定都沒有成熟。所以C(N) = C(N-1) + C(N-3)。該問題同樣也可以使用矩陣乘法的方式,只不過這裡是三階遞推數列,原理同上,詳情見如下程式碼。
下面是使用python3.5實現的程式碼。
#母牛數量問題
#遞迴
def fibonacci3(n):
if n < 1 :
return 0
if n == 1 or n == 2 or n == 3:
return n
return fibonacci3(n-1) + fibonacci3(n-3)
#動態規劃
def fibonacci4(n):
if n < 1:
return 0
if n == 1 or n == 2 or n == 3:
return 3
prepre = 1
pre = 2
cur = 3
for i in range(4, n+1):
tmp = cur
cur = prepre + cur
prepre = pre
pre = tmp
return cur
#矩陣乘法
def fibonacciUseMatrix2(n):
def matrixPower(m, p):
res = [[1 if i == j else 0 for i in range(len(m[0]))] for j in range(len(m))]
tmp = m
while p > 0:
if p & 1 != 0:
res = muliMatrix(res, tmp)
tmp = muliMatrix(tmp, tmp)
p >>= 1
return res
def muliMatrix(m1, m2):
res = [[0 for i in range(len(m2[0]))] for j in range(len(m1))]
for i in range(len(m1)):
for j in range(len(m2[0])):
for k in range(len(m1[0])):
res[i][j] += m1[i][k] * m2[k][j]
return res
if n < 1:
return 0
if n == 1 or n ==2 or n == 3:
return n
base = [[1,1,0], [0,0,1], [1,0,0]]
res = matrixPower(base, n-3)
return 3 * res[0][0] + 2 * res[1][0] + res[2][0]