遞迴與動態規劃---最長遞增子序列問題
阿新 • • 發佈:2018-12-24
【問題】
給定陣列arr,返回arr的最長遞增子序列
【基本思路】
首先介紹時間複雜度為O(N^2)的方法。具體過程如下:
生成長度為N(arr的長度)的陣列dp,dp[i]表示在以arr[i]結尾的情況下,arr[0…i]中的最長子序列。
dp[0]表示以arr[0]結尾的情況下最長子序列,只有它自己,設為1
- 對於dp的其他位置,從左到右依次遍歷,假設遍歷到i,首先在arr[0…i-1]中找到比arr[i]小且相應的dp值最大的位置記為j,arr[j]即為以arr[i]結尾的倒數第二小的數,此時dp[i]的值便可以確定,dp[i] = dp[j] + 1。如果arr[0…i-1]中沒有比arr[i]小的值,則dp[i]直接記為1。
接下來就是利用生成好的dp陣列得到最長的遞增子序列。
首先遍歷找到dp陣列中的最大值maxlen以及下標index,其中maxlen就是最長遞增子序列的長度,arr[index]就是最長遞增子序列的最後一個數字,然後從index向前遍歷陣列arr,找到比arr[index]小的數arr[j]並且dp[j] + 1 = dp[index],這個值就是子序列的倒數第二個數,依次向前遍歷即可得到最長遞增子序列。
以下是使用python3.5實現的程式碼
#最長遞增子序列
def getMaxSubList1(arr):
def getdp(arr):
dp = [1 for i in range(len(arr))]
for i in range(len(arr)):
for j in range(i):
if arr[i] > arr[j]:
dp[i] = max(dp[i], dp[j]+1)
return dp
def generateLIS(arr, dp):
maxlen = 0
index = 0
for i in range(len(dp)):
if dp[i] > maxlen:
maxlen = dp[i]
index = i
lis = [ for i in range(maxlen)]
lis[maxlen-1] = arr[index]
maxlen -= 1
for i in range(index, -1, -1):
if arr[i] < arr[index] and dp[i]+1 == dp[index]:
lis[maxlen-1] = arr[i]
maxlen -= 1
index = i
return lis
if arr == None or len(arr) == 0:
return None
dp = getdp(arr)
return generateLIS(arr, dp)
接下里介紹一個時間複雜度為O(NlogN)的方法。
該方法是在生成dp陣列的時候利用二分查詢來進行優化,通過另外一個輔助陣列ends完成。ends[b]的含義為遍歷到目前位置,長度為b + 1的子序列的最小結尾。過程如下:
- 生成長度為N的dp陣列和ends陣列,令dp[0] = 1,ends[0] = arr[0]。
- 從左到右遍歷arr的剩餘部分,假設遍歷到位置i,首先在ends中已有的數值中找第一個比arr[i]大的數的位置k(使用二分查詢),把該位置的數替代為arr[i],dp[i] = k + 1。依次遍歷即可得到dp陣列。
def getMaxSubList2(arr):
def getdp2(arr):
dp = [0 for i in range(len(arr))]
ends = [0 for i in range(len(arr))]
right = 0
dp[0] = 1
ends[0] = arr[0]
for i in range(1, len(arr)):
l = 0
r = right
while l <= r:
m = (l + r) // 2
if arr[i] > ends[m]:
l = m + 1
else:
r = m - 1
right = max(right, l)
dp[i] = l + 1
ends[l] = arr[i]
return dp
def generateLIS(arr, dp):
maxlen = 0
index = 0
for i in range(len(dp)):
if dp[i] > maxlen:
maxlen = dp[i]
index = i
lis = [0 for i in range(maxlen)]
lis[maxlen-1] = arr[index]
maxlen -= 1
for i in range(index, -1, -1):
if arr[i] < arr[index] and dp[i]+1 == dp[index]:
lis[maxlen-1] = arr[i]
maxlen -= 1
index = i
return lis
if arr == None or len(arr) == 0:
return None
dp = getdp2(arr)
return generateLIS(arr, dp)