问题描述
已知两个固定字母序列,求解两者最长(非连续)子序列长度
实现思路
使用动态规划思想,将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']