最长公共子序列

例:

A=['A','B','C','B','D','A','B']
B=['B','D','C','A','B','A']

最长公共子序列是BCBA或BDAB,子序列可以不是连续的,相对顺序一样就可以。

这是一道动态规划题,首先我们需要一个c[a+1][b+1]来记录状态,注意每一维需要比数组长1,为了保存当A,B为空时候的情况。然后我们从[0,0]开始按行填表。按如下公式进行填表

c[i,j]=\left\{\begin{matrix} 0 & i,j=0 \\ c[i-1][j-1]+1 & i,j>0 \,\,\, A[i]=B[j]\\ max(c[i-1][j],c[i][j-1])& i,j>0 \, A[i]\neq B[j] \end{matrix}\right.

我们想象一下AB两个数组最后一个元素如果是相同的,那么它肯定在最长公共子序列里,那么问题就缩小为去掉最后一个元素找子序列的问题。如果最后一个元素不一样,这里就有分支了,我可以从A中去掉一个,也可以从B中去掉一个,最后我肯定是要选择收益最高的那个。

A=['A','B','C','B','D','A','B']
B=['B','D','C','A','B','A']
len_a = len(A)
len_b = len(B)
c=[[0 for i in range(len_b+1)]for j in range(len_a+1)]
for i in range(len_a):
    for j in range(len_b):
        if A[i] == B[j]:
            c[i+1][j+1] = c[i][j] + 1
        elif c[i+1][j] > c[i][j+1]:
            c[i+1][j+1] = c[i+1][j]
        else:
            c[i+1][j+1] = c[i][j+1]
i=len_a
j=len_b
ans=[]
while i>0 and j>0:
    if A[i-1]==B[j-1]:
        ans.append(A[i-1])
        i=i-1
        j=j-1
    else:
        if c[i-1][j]>c[i][j-1]:
            i=i-1
        else:
            j=j-1
print(ans)
#['B', 'A', 'D', 'B']
print (c[len_a][len_b])
#4

最后最长的长度在表中的右下角,现在只得到了长度,如果想获得具体的序列,还需要回溯。我们从右下角开始,如果A,B元素相同,那么这个元素就在序列里,同时它的状态是从[i-1][j-1]得来的,所以回溯到[i-1][j-1]。如果不相同,就看它是从哪个分支过来的,我们走较大的那个分支。如果两个分支是相等的,我们就选一个方向,注意回溯的时候处理相等的情况需要从始至终选定一个方向,最终回溯到i,j有一个是0为止。因为有相等的情况出现,所以最长子序列不一定唯一

参考

https://blog.csdn.net/someone_and_anyone/article/details/81044153

https://blog.csdn.net/littlethunder/article/details/25637173

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值