問題描述
已知兩個固定字母序列,求解兩者最長(非連續)子序列長度
實現思路
使用動態規劃思想,將a序列的i長度子序列與b序列的j長度子序列的最長公共子序列看作子問題 s[i,j]
則s[i,j]滿足如下公式
代碼實現
子序列矩陣
import numpy as np
def dplcs(str1, str2):
s = np.zeros((len(str1) + 1, len(str2) + 1), dtype = np.uint8)
s[:, 0] = 0
s[0, :] = 0
for i in range(len(str1)):
for j in range(len(str2)):
if str1[i] == str2[j]:
s[i + 1, j + 1] = s[i, j] + 1
else:
s[i + 1, j + 1] = max(s[i, j + 1], s[i + 1, j])
return s
a = 'fdjkaspewfnklvd;f'
b = 'fdasjnfxc.vpowewf['
rect = dplcs(a, b)
輸出如下,則最長子序列長度爲右下角值8
[[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
[0 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]
[0 1 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3]
[0 1 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3]
[0 1 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3]
[0 1 2 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4]
[0 1 2 3 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5]
[0 1 2 3 4 4 4 4 4 4 4 4 5 5 5 6 6 6 6]
[0 1 2 3 4 4 4 4 4 4 4 4 5 5 6 6 7 7 7]
[0 1 2 3 4 4 4 5 5 5 5 5 5 5 6 6 7 8 8]
[0 1 2 3 4 4 5 5 5 5 5 5 5 5 6 6 7 8 8]
[0 1 2 3 4 4 5 5 5 5 5 5 5 5 6 6 7 8 8]
[0 1 2 3 4 4 5 5 5 5 5 5 5 5 6 6 7 8 8]
[0 1 2 3 4 4 5 5 5 5 5 6 6 6 6 6 7 8 8]
[0 1 2 3 4 4 5 5 5 5 5 6 6 6 6 6 7 8 8]
[0 1 2 3 4 4 5 5 5 5 5 6 6 6 6 6 7 8 8]
[0 1 2 3 4 4 5 6 6 6 6 6 6 6 6 6 7 8 8]]
最長子序列獲取
最長子序列一般都有多種可能,這裏給出其中一種的獲取代碼
def rdlcs(str1, str2, rect):
i = len(str1)
j = len(str2)
idx_arr = []
while (rect[i, j] > 0):
if rect[i, j] == rect[i - 1, j]:
i -= 1
continue
if rect[i, j] == rect[i, j - 1]:
j -= 1
else:
i -= 1
j -= 1
idx_arr.append((i, j))
idx_arr.reverse()
print(idx_arr)
print(np.array([s for s in str1])[[x[0] for x in idx_arr]])
rdlcs(a, b, rect.astype(np.uint8))
輸出如下:
[(0, 0), (1, 1), (4, 2), (5, 3), (6, 11), (7, 14), (8, 15), (9, 16)]
['f' 'd' 'a' 's' 'p' 'e' 'w' 'f']