[python] 获得所有的最长公共子序列
两句闲话
得到两个序列的最长公共子序列(LCS)是个经典问题,使用动态规划,实现起来并不难。
一般来说,我们只是输出一个LCS。但是,老师布置的作业是输出所有的LCS。
解法
按照一般的方法,我们首先得到一个矩阵,然后从矩阵的右下角开始回溯。回溯时,我们选择较大的数字,以向左,或向上,或向左上。但当数字相等时,我们往往会随便向某一个方向回溯,这样的话,我们就只会得到一个LCS。因此,很容易想到,所有的LCS会构成一棵树,我们只需要对这棵树进行先序遍历,就可得到所有的LCS。
代码如下
#python 3.5 class LCS_naive: """ 最长公共子序列: 通过动态规划,得到矩阵D, 并从矩阵D中读出一个最长公共子序列 不支持读出所有的LCS """ def __init__(self): self.matrix=[[]] def init(self,str1,str2): self.str1=str1 self.str2=str2 self.len1=len(str1) self.len2=len(str2) self.matrix=[[0 for i in range(self.len2+1)]for j in range(self.len1+1)] def _get_matrix(self): """通过动态规划,构建矩阵""" for i in range(self.len1): for j in range(self.len2): if self.str1[i]==self.str2[j]: self.matrix[i+1][j+1]=self.matrix[i][j]+1 else: self.matrix[i+1][j+1]=max(self.matrix[i][j+1],self.matrix[i+1][j]) def _matrix_show(self,matrix): """展示通过动态规划所构建的矩阵""" print ("----matrix-----") print (" "," ",end=" ") for ch in self.str2: print (ch,end=" ") print () for i in range(len(matrix)): if i>0: print (self.str1[i-1],end=" ") else: print (" ",end=" ") for j in range(len(matrix[i])): print (matrix[i][j],end=" ") print () print ("---------------") def _get_one_lcs_from_matrix(self): i=len(self.matrix)-1 if i==0: print ("matrix is too small") return j=len(self.matrix[0])-1 res=[] while not (i==0 or j==0): if self.str1[i-1]==self.str2[j-1]: res.append(self.str1[i-1]) i-=1 j-=1 else: if self.matrix[i-1][j]>self.matrix[i][j-1]: i=i-1 else: j=j-1 return "".join(res[::-1]) def get_lcs(self): self._get_matrix() self._matrix_show(self.matrix) lcs=self._get_one_lcs_from_matrix() print (lcs) class LCS(LCS_naive): """ 继承自LCS_naive 增加获取所有LCS的支持 """ def __init__(self): LCS_naive.__init__(self) def _get_all_lcs_from_matrix(self): self._pre_travesal(self.len1,self.len2,[]) def _pre_travesal(self,i,j,lcs_ted): if i==0 or j==0: print ("".join(lcs_ted[::-1])) return if self.str1[i-1]==self.str2[j-1]: lcs_ted.append(self.str1[i-1]) self._pre_travesal(i-1,j-1,lcs_ted) else: if self.matrix[i-1][j]>self.matrix[i][j-1]: self._pre_travesal(i-1,j,lcs_ted) elif self.matrix[i-1][j]<self.matrix[i][j-1]: self._pre_travesal(i,j-1,lcs_ted) else: ###### 分支 self._pre_travesal(i-1,j,lcs_ted[:]) self._pre_travesal(i,j-1,lcs_ted) def get_lcs(self): self._get_matrix() self._matrix_show(self.matrix) self._get_all_lcs_from_matrix() l=LCS() l.init("ABCBDAB","BDCABA") l.get_lcs()
输出结果
----matrix----- B D C A B A 0 0 0 0 0 0 0 A 0 0 0 0 1 1 1 B 0 1 1 1 1 2 2 C 0 1 1 2 2 2 2 B 0 1 1 2 2 3 3 D 0 1 2 2 2 3 3 A 0 1 2 2 3 3 4 B 0 1 2 2 3 4 4 --------------- BCBA BCAB BDAB
posted on 2017-03-01 21:35 SuperZhang828 阅读(2327) 评论(0) 编辑 收藏 举报