python实现求字符串最长公共子串

本文主要参考http://www.cnblogs.com/ider/p/longest-common-substring-problem-optimization.html的讲解,本人自己用python实现了一下暴力法,动态规划。


# coding: utf-8

# ## 最长公共子串问题
# 
# ### 暴力法求解  VS  动态规划
# 
# ### 参考自http://www.cnblogs.com/ider/p/longest-common-substring-problem-optimization.html
# 

# ## 方法一:暴力法求解
# ### 时间复杂度(o^3),空间复杂度(1)

# In[2]:

get_ipython().magic('pdb on')


# In[1]:

import numpy as np


# In[18]:

# 获取字符串str1和str2最长公共子串的长度与起始位置
def getLongestSubstring(str1,str2):
    longest=0
    start_pos1=-1
    start_pos2=-1
    compares=0   # 记录比较次数

    for i in range(len(str1)):
        for j in range(len(str2)):
            length=0
            m=i
            n=j
            while str1[m]==str2[n]:
                compares+=1
                length+=1
                m+=1
                n+=1
                if (m>=len(str1))|(n>=len(str2)):
                    break
            if longest<length:
                compares+=1
                longest=length
                start_pos1=i
                start_pos2=j
    return longest,start_pos1,start_pos2,compares


# ## 方法二:动态规划
# ### 未优化时,时间复杂度(o^2),空间复杂度(o^2)

# In[17]:

# 通过动态规划的方法优化求解最长公共子串
def getLongestSubstring_dp(str1,str2):
    str1_len=len(str1)
    str2_len=len(str2)
    compares=0
    if (str1_len==0)|(str2_len)==0:
        return -1

    # 定义一个二维数据记录最长子串长度
    m=np.zeros([str1_len,str2_len],dtype=np.int)

    for j in range(str2_len):
        compares+=1
        m[0][j]=1 if str1[0]==str2[j] else 0

    for i in range(1,str1_len):
        compares+=1
        m[i][0]=1 if str1[i]==str2[0] else 0

        for j in range(1,str2_len):
            compares+=1
            m[i][j]=m[i-1][j-1]+1 if str1[i]==str2[j] else 0

    # 寻找矩阵中最大的数,也就是最长公共子串的长度
    longest=0
    start_pos1=-1
    start_pos2=-1
    for i in range(str1_len):
        for j in range(str2_len):
            if longest<m[i][j]:
                longest=m[i][j]
                start_pos1=i-longest+1
                start_pos2=j-longest+1

    return longest,start_pos1,start_pos2,compares


# ### 优化后,时间复杂度(o^2),空间复杂度(n)

# In[16]:

def getLongestSubstring_dp2(str1,str2):
    str1_len=len(str1)
    str2_len=len(str2)

    if (str1_len==0)|(str2_len==0):
        return -1

    start_pos1=0
    start_pos2=0
    longest=0
    compares=0

    m=np.zeros([2,str2_len],dtype=np.int)  # 只用两行就可以计算最长子串长度

    for j in range(str2_len):
        if str1[0]==str2[j]:
            compares+=1
            m[0][j]=1
            if longest==0:
                longest=1
                start_pos1=0
                start_pos2=j

    for i in range(1,str1_len):

        # 通过且运算计算出当前行和先前行
        cur=int((i&1)==1)
        pre=int((i&1)==0)

        if str1[i]==str2[0]:
            compares+=1
            m[cur][0]=1
            if longest==0:
                longest=1
                start_pos1=i
                start_pos2=0

        for j in range(1,str2_len):
            if str1[i]==str2[j]:
                compares+=1
                m[cur][j]=m[pre][j-1]+1
                if longest<m[cur][j]:
                    longest=m[cur][j]
                    start_pos1=i-longest+1
                    start_pos2=j-longest+1

    return longest,start_pos1,start_pos2,compares



# ## 测试

# In[19]:

str1='abcababdcababc'
str2='ababc'

length,s1,s2,com=getLongestSubstring(str1,str2)
print(length,s1,s2,com)

length,s1,s2,com=getLongestSubstring_dp(str1,str2)
print(length,s1,s2,com)

length_3,s1_3,s2_3,com_3=getLongestSubstring_dp2(str1,str2)
print(length,s1,s2,com)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值