最长公共子串 和 最长公共子序列 的python算法实现

本文介绍如何使用动态规划算法求解两个字符串的最长公共子串和最长公共子序列,并提供了详细的Python代码实现。适用于生物信息学、文本比对等领域。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

《算法图解》第9章 动态规划 后面给出了怎么求两个字符串的 最长公共字串 和 最长公共子序列 的算法思路。但是没有给出代码实现,这里根据其思路实现其算法python编程。

  1. 最长公共字串
    为两个字符串a, b中相同的连续字符串的长度。
    如 a=‘yhabcfdaefch’ , b=‘abcfaaegh’
    则a,b的最长公共子串为’abcf’
    思路如下:
    在这里插入图片描述
    代码如下:
import numpy as np

word_a='ABCEDFE'  
word_b='AGHCDE' 

len_a=len(word_a) 
len_b=len(word_b) #获取字符串a,b的长度
word_a=[word_a[i] for i in range(len_a)] #为了后续方便计算,将字符串转换成列表
word_b=[word_b[i] for i in range(len_b)] 

cell=np.zeros((len_a+1,len_b+1),dtype=int)  #考虑到迭代需要用到cell[i-1,j-1],
                                    #为了不超出范围,因此设置网格大小为:(len_a+1,len_b+1)

for i in range(1,len_a+1):
    for j in range(1,len_b+1):
        if word_a[i-1]==word_b[j-1]: #如果两个字母相同
            cell[i][j]=cell[i-1][j-1]+1 #值为左上角邻居的值加1
        else:  
            cell[i][j]=0 #如果两个字母不相同,值为0
            
#到这一步已经完成了获取最长公共子串长度的计算,但是还不知道最长公共子串是什么
#以下几行代码的作用就是获取最长公共字串

max_same_seq_len=np.max(cell) #获取最长公共字串的长度
index=np.where(cell==max_same_seq_len)  #最长公共字串的最后一个字符在cell上的位置

num_max_same_seq=len(index[0])  #获取最长公共子串的数量
print('最长公共子串数量有: ',num_max_same_seq, '个') 

for i in range(num_max_same_seq):
    
    index_a=int(index[0][i]) #行表示该最长公共字串的最后一个字符在字符串a上的位置索引
    max_same_seq=word_a[index_a-max_same_seq_len:index_a]  #根据该最长子串的起始位置获取该					 
                                                                                              				#最长子串
    
    #以下代码等价
    #index_b=int(index[1][i]) #列表示该最长公共字串的最后一个字符在字符串b上的位置索引
    #max_same_seq=word_b[index_b-max_same_seq_len:index_b]

    print('第',i, '个最长公共子串为:',max_same_seq)
    print()

根据上述代码中的例子,运行结果如下:
在这里插入图片描述

  1. 最长公共子序列
    如 a=‘yhabcfdaefhc’ , b=‘abcfaaegh’
    则a,b的最长公共子序列为’abcfaeh’

思路为:
在这里插入图片描述
在这里插入图片描述

import numpy as np
word_a='ABCEFE'  
word_b='ABHCEE' 

len_a=len(word_a) 
len_b=len(word_b) #获取字符串a,b的长度
word_a=[word_a[i] for i in range(len_a)] #为了后续方便计算,将字符串转换成列表
word_b=[word_b[i] for i in range(len_b)] 

#求最长公共子序列
grid=np.zeros((len_a+1,len_b+1),dtype=int) #考虑到迭代需要用到gridll[i-1,j-1],
                                    #为了不超出范围,因此设置网格大小为:(len_a+1,len_b+1)
for i in range(1,len_a+1):
    for j in range(1,len_b+1):
        if word_a[i-1]==word_b[j-1]: #如果两个字母相同
            grid[i][j]=grid[i-1][j-1]+1 #值为左上角邻居的值加1
        else:  
            grid[i][j]=max(grid[i-1][j],grid[i][j-1]) #如果两个字母不相同,就选择上方和左方邻居中交大的那个           
 
max_seq_len=np.max(grid) #获取最长公共字串的长度
max_seq=[] #最长公共字串列表

while max_seq_len:
    
    index=np.where(grid==max_seq_len) #最长公共子序列长度对应的数值在grid上的位置
    
    index_b=int(min(index[1])) #取该值对应的最小列的索引
    
    max_seq.append(word_b[index_b-1])  #将索引位置对应的字符加入 max_seq里面去   
    
    max_seq_len=max_seq_len-1  #最长公共子序列长度-1,以寻找下一个公共字符
    
max_seq=[max_seq[len(max_seq)-i-1] for i in range(len(max_seq))] #将确定的最长公共子序列逆序

print('最长公共子序列为:',max_seq)

运行结果为:
在这里插入图片描述

总结:这两个算法的应用场景很多,如生物学家根据最长公共序列来确定DNA链的相似性,如指出两个文件的差异性等。都属于动态规划的一种。而动态规划中最重要的一个环节就是确定网格值的迭代公式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值