遞迴二 遞迴的優化,DP

2021-08-21 12:59:23 字數 2911 閱讀 3338

上課時給學生講到遞迴實現的缺陷時,舉過下面的例子:

使用遞迴方法來計算組合數:

從m個不同元素中,任取n(n≤m)個元素並成一組,叫做從m個不同元素中取出n個元素的乙個組合;從m個不同元素中取出n(n≤m)個元素的所有組合的個數,叫做從m個不同元素中取出n個元素的組合數。

公    式: c(m,n)=n!/((m-n)!*n!)(n≤m)

性    質:c(m,n)= c(m,m-n)                  --可以推導出--》 c(m,0) = c(m,m) = 1

c(m,n)=c(m-1,n-1)+c(m-1,n)

請使用遞迴的方法來計算組合數。

使用遞迴的方法很簡單,使用我們之前講過的遞迴的原則:

如上圖,當我們來計算c(6,4)時,我們需要計算c(5,3)和c(5,4),而計算c(5,3)又要計算c(4,2)和c(4,3),依次 類推。

我們發現這裡有大量的重複預算。這也就是為什麼遞迴在時間和空間(遞迴要開闢棧空間)上有大量的資源消耗。

那麼問題來了,我們需要怎麼來優化?

根據上一章所講的內容,我們可以嘗試用迴圈來優化遞迴。這裡我們使用另一種方法,dp(dynamical programming),也就是動態規劃的方法來優化。

我們考慮:這裡有很多中間結果被反覆計算,從而引起了時間和空間上(遞迴需要分配棧空間)的浪費,

所以我們可以考慮將計算的中間結果記錄在某處,然後當再次需要這個結果時,從已經計算的結果中來查詢,從而得到結果,

這樣在時間上可以節省大量的成本,當然,空間上則需要一定輔助空間。

按照這個思路,我們嘗試用一張大的表來有序的儲存中間結果。

如下圖,我們讓行對應m,讓列對應n,這樣我們根據c(m,0) = c(m,m) = 1,可以將下標中

的黑色區域填上初始值1;

然後根據性質:c(i,j)=c(i-1,j-1)+c(i-1,j)

我們找到了計算出c(i,j)的方法,所以在計算c(5,2)

時可以使用c(4,1)+c(4,2)=4+6=10

依次類推:

我們可以計算出表中的c(m,n);

於是,有了下面的演算法2(dynamical programming)實現:

import math

import time

def combinationnum2(m,n):

#arr = [[0]*m]*n  # row m, coloumn n

t1 = time.time()

mylist = [([0] * (n+1)) for i in range(m+1)]

#print(mylist)

for i in range(0, m-n+1):

mylist[i][0] = 1

for i in range(0,n+1):

mylist[i][i] = 1

#print(mylist)

for j in range(1, n+1):

for i in range(j+1, m-n+j+1):

mylist[i][j] = mylist[i-1][j-1]+mylist[i-1][j]

#print(mylist)

print("combinationnum2 costed %f seconds"%(time.time()-t1))

return mylist[m][n]

#return combinationnum(m-1,n-1)+ combinationnum(m-1,n)

這裡我們就是乙個使用dp的思想來優化遞迴的案例。

# 當然,我們可以從數學公式的角度來解決這個問題,**如下:

def combinationnum3(m,n):

t1 = time.time()

result = math.factorial(m)/(math.factorial(m-n)*math.factorial(n))

print("combinationnum3 costed %f seconds"%(time.time()-t1))

return result

# 測試**:

m = int(raw_input("please input m:"))

n = int(raw_input("please input n:"))

print(combinationnum2(m, n))

print(combinationnum3(m, n))

對python演算法,爬蟲和資料分析感興趣的朋友可以加入qq群:748905525,一起學習討論

遞迴 遞迴的優化

遞迴演算法在工作或者各種資料結構中使用比較頻繁,遞迴演算法的簡化常見有自頂向下還有備忘錄法 自頂向下 t n t1 n t2 n t3 n 25c t1 n r11p1 r12p2 r13p3 r14p4 r15p5 r16p6 r17p7 r18p8 r19p9 t1 n 1 x tau1 t1 ...

遞迴 遞迴演算法的非遞迴優化

一 遞迴 在方法內部呼叫自身方法的過程稱為遞迴,下面給出乙個遞迴方法的示例。class program 使用遞迴,實現求前n項和 public static int getsum int n int result getsum n 1 在方法體中呼叫方法本身 return result n 需要注意...

普通遞迴與優化遞迴

function factorial n factorial 5 120 上面 是乙個階乘函式,計算n的階乘,最多需要儲存n個呼叫記錄,複雜度 o n 如果改寫成尾遞迴,只保留乙個呼叫記錄,複雜度 o 1 函式呼叫自身,稱為遞迴。如果尾呼叫自身,就稱為尾遞迴。遞迴非常耗費記憶體,因為需要同時儲存成千...