dp基礎之序列型最長上升子序列
阿新 • • 發佈:2018-11-19
問題 :給定a[i](i=0...n-1),找到最長上升子序列(假設長度為k),輸出k
例:
a = [4,2,4,5,3,7]
返回
k=4([2,4,5,7])
分析:
對於最優策略:一定有最後一個元素a[j]
情況1:最優策略就是{a[j]},長度k就是1
情況2:最優策略子序列長度大於1,則最優策略中最後一個元素a[j]前一定有一個元素a[i],且a[i]<a[j](i<j)
且以a[i]結尾的序列列也是最優的
子問題:f[i]表示以a[i]結尾的最長子序列長度
f[i] = max{1,f[i]+1 | i<j && a[i]<a[j] }
計算順序:
f[0]...f[n-1]
時間複雜度O(n^2) ,空間複雜度O(n)
程式碼及註釋如下:
def long_sequence(a): #f[i]表示以a[i]結尾的上升子序列的長度 n = len(a) if n == 0: return ; f = [0 for j in range(n)] #初始,以a[0]結尾的最長上升子序列長度就是1 for j in range(n): #情況1,f[0] = 1 f[j] = 1 #列舉j之前最優子序列長度 for i in range(j): if a[i] < a[j] and f[j] < f[i]+1: f[j] = f[i] + 1 return max(f) a = [4,2,4,5,3,7] print(long_sequence(a)) #結果:4
信封問題跟這個類似,就放一起比較
問題:給定N個信封的長和寬,如果另一個信封的長和寬更小,則可以被套進信封去,問,最多巢狀多少個信封?
分析:
確定狀態:
先考慮長度,將所有信封長度從小到大排序
設:最優策略裡最外層信封的長度時Ej,則
次外層信封的長度Ei,也是最優策略,且Ei<Ej(i<j)
子問題:要知道以Ej結尾的最優策略的長度,則我們需要知道以Ei結尾的最優策略
設f[i]是以Ei為最外層信封的最優策略的信封數
f[i] = max{i, f[j] + 1 | Ej在Ei裡,j<i}
無初始條件
依次求f[0],...,f[n-1]
需要對信封長度排序,時間複雜度O(N^2),空間複雜度O(N)
程式碼及註釋如下:
def doll_envelope(E):
n = len(E)
if n == 0:
return 0
#f[i]是以Ei為最外層信封的最優策略的信封數
f = [0 for i in range(n)]
for i in range(n):
#f[0] = 1
f[i] = 1
for j in range(i):
#前面的長度小且寬度小,信封j可以放到信封i裡
if E[j][0] < E[i][0] and E[j][1] < E[i][1]:
f[i] = max(f[i],f[j] + 1)
return max(f)
A = [[5,4],[6,4],[6,7],[2,3]]
E = sorted(A)
print(doll_envelope(E))
#結果:3
未完待續。。。