深入解析最长公共子串

深入解析最长公共子串

什么是最长公共子串

最长公共子串(Longest Common Substring)是指两个或多个字符串中最长的子串,它可以用来比较两个字符串的相似程度。

例如,对于字符串 "abcdefg" 和 "defghij",它们的最长公共子串为 "defg",长度为 4。即 "abcdefg" 中的 "defg" 与 "defghij" 中的 "defg" 相同。

暴力解法

最简单的方法就是暴力枚举,我们依次枚举字符串 S1 和 S2 中的每个子串,然后判断该子串是否为它们的公共子串。最后找到长度最长的那个子串。

最坏时间复杂度为 $O(n^3)$,不适合处理大规模数据。

下面是暴力解法的伪代码:

for i from 0 to len(S1)
    for j from 0 to len(S2)
        for k from 0 to len(S1) - i and len(S2) - j
            if S1[i:i+k] == S2[j:j+k] and k > ans
                ans = k
                lcs = S1[i:i+k]
return lcs

动态规划解法

动态规划是一种时间复杂度为 $O(n^2)$ 的解法,它把问题拆解成若干个子问题,然后通过求解子问题的最优解,得到原问题的最优解。

对于字符串 S1 和 S2,我们定义二维数组 dp,其中 dp[i][j] 表示 S1[0:i] 和 S2[0:j] 的最长公共子串长度。

如果 S1[i] == S2[j],那么 dp[i][j] = dp[i-1][j-1] + 1,否则 dp[i][j] = 0。

下面是动态规划解法的伪代码:

dp = [[0 for _ in range(len(S2))] for _ in range(len(S1))]
ans = 0
lcs = ''
for i from 0 to len(S1)
    for j from 0 to len(S2)
        if S1[i] == S2[j]
            if i == 0 or j == 0
                dp[i][j] = 1
            else
                dp[i][j] = dp[i-1][j-1] + 1
        if dp[i][j] > ans
            ans = dp[i][j]
            lcs = S1[i-ans+1:i+1]
return lcs

示例解释

示例1

假设有字符串 S1 和 S2 分别为 "abcde" 和 "bcdfg",它们的最长公共子串为 "bcd",长度为 3。我们可以运用暴力解法和动态规划解法来进行验证。

暴力解法的伪代码为:

for i from 0 to len(S1)
    for j from 0 to len(S2)
        for k from 0 to len(S1) - i and len(S2) - j
            if S1[i:i+k] == S2[j:j+k] and k > ans
                ans = k
                lcs = S1[i:i+k]
return lcs

按照该算法步骤,有:

当 i=0, j=0, k=1 时,k=1, ans=1, lcs='a';

当 i=0, j=1, k=1 时,k=1, ans=1, lcs='b';

当 i=0, j=2, k=1 时,k=1, ans=1, lcs='c';

当 i=0, j=3, k=1 时,k=1, ans=1, lcs='d';

当 i=0, j=4, k=1 时,k=1, ans=1, lcs='e';

当 i=1, j=0, k=1 时,k=1, ans=1, lcs='b';

当 i=1, j=1, k=3 时,k=3, ans=3, lcs='bcd';

当 i=1, j=2, k=1 时,k=1, ans=3, lcs='bcd';

当 i=1, j=3, k=1 时,k=1, ans=3, lcs='bcd';

当 i=2, j=0, k=1 时,k=1, ans=3, lcs='bcd';

当 i=2, j=1, k=1 时,k=1, ans=3, lcs='bcd';

当 i=2, j=2, k=1 时,k=1, ans=3, lcs='bcd';

当 i=3, j=0, k=1 时,k=1, ans=3, lcs='bcd';

当 i=3, j=1, k=1 时,k=1, ans=3, lcs='bcd';

当 i=4, j=0, k=1 时,k=1, ans=3, lcs='bcd';

最后得到 lcs='bcd'。

动态规划解法的伪代码为:

dp = [[0 for _ in range(len(S2))] for _ in range(len(S1))]
ans = 0
lcs = ''
for i from 0 to len(S1)
    for j from 0 to len(S2)
        if S1[i] == S2[j]
            if i == 0 or j == 0
                dp[i][j] = 1
            else
                dp[i][j] = dp[i-1][j-1] + 1
        if dp[i][j] > ans
            ans = dp[i][j]
            lcs = S1[i-ans+1:i+1]
return lcs

按照该算法步骤,有:

当 i=0, j=0, S1[i]='a', S2[j]='b' 时,dp[0][0]=0;

当 i=0, j=1, S1[i]='a', S2[j]='c' 时,dp[0][1]=0;

当 i=0, j=2, S1[i]='a', S2[j]='d' 时,dp[0][2]=0;

当 i=0, j=3, S1[i]='a', S2[j]='e' 时,dp[0][3]=0;

当 i=0, j=4, S1[i]='a', S2[j]='f' 时,dp[0][4]=0;

当 i=1, j=0, S1[i]='b', S2[j]='b' 时,dp[1][0]=1;

当 i=1, j=1, S1[i]='b', S2[j]='c' 时,dp[1][1]=0;

当 i=1, j=2, S1[i]='b', S2[j]='d' 时,dp[1][2]=1;

当 i=1, j=3, S1[i]='b', S2[j]='e' 时,dp[1][3]=0;

当 i=1, j=4, S1[i]='b', S2[j]='f' 时,dp[1][4]=0;

当 i=2, j=0, S1[i]='c', S2[j]='b' 时,dp[2][0]=0;

当 i=2, j=1, S1[i]='c', S2[j]='c' 时,dp[2][1]=1;

当 i=2, j=2, S1[i]='c', S2[j]='d' 时,dp[2][2]=0;

当 i=2, j=3, S1[i]='c', S2[j]='e' 时,dp[2][3]=0;

当 i=2, j=4, S1[i]='c', S2[j]='f' 时,dp[2][4]=0;

当 i=3, j=0, S1[i]='d', S2[j]='b' 时,dp[3][0]=0;

当 i=3, j=1, S1[i]='d', S2[j]='c' 时,dp[3][1]=0;

当 i=3, j=2, S1[i]='d', S2[j]='d' 时,dp[3][2]=1;

当 i=3, j=3, S1[i]='d', S2[j]='e' 时,dp[3][3]=0;

当 i=3, j=4, S1[i]='d', S2[j]='f' 时,dp[3][4]=0;

当 i=4, j=0, S1[i]='e', S2[j]='b' 时,dp[4][0]=0;

当 i=4, j=1, S1[i]='e', S2[j]='c' 时,dp[4][1]=0;

当 i=4, j=2, S1[i]='e', S2[j]='d' 时,dp[4][2]=0;

当 i=4, j=3, S1[i]='e', S2[j]='e' 时,dp[4][3]=0;

当 i=4, j=4, S1[i]='e', S2[j]='f' 时,dp[4][4]=0;

最后得到 lcs='bcd'。

总结

动态规划解法是最长公共子串问题的高效解法,与暴力枚举法不同,它通过解决子问题的最优解,得到原问题的最优解。但是,用动态规划求解的空间和时间复杂度都比较高,如果 S1 和 S2 的长度较大,则需要引入优化、精简算法等措施处理。

如有问题,欢迎指正。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入解析最长公共子串 - Python技术站

(1)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • C#常用的数据格式转换汇总

    C#常用的数据格式转换汇总 在C#中,常常需要将各种数据类型互相转换,比如将字符串转换成整数、将整数转换成字符串等。本文将为大家介绍C#中常用的数据格式转换方法。 1. int和string之间的转换 1.1 int转string 将int类型的变量转换成string类型,可以使用ToString()方法。示例代码如下: int num = 123; str…

    C 2023年5月23日
    00
  • C语言小程序有哪些 经典C语言小程序举例说明

    编写C语言小程序的攻略 1. 了解基本语法 在学习和编写C语言小程序之前,我们需要先掌握C语言的基础语法,包括数据类型、变量、算术运算、流程控制语句、函数等等。可以通过教材、网上课程或者在线编程平台来学习和练习。 2. 掌握IDE环境 为了编写和调试C语言小程序,我们需要选择一个合适的IDE环境,例如Visual Studio Code、Code:Block…

    C 2023年5月30日
    00
  • Java实现学生成绩管理系统

    Java实现学生成绩管理系统完整攻略 搭建环境1. 安装Java开发工具包(JDK)2. 安装Java集成开发环境(IDE),如Eclipse、IntelliJ IDEA等 设计数据库1. 使用MySQL等数据库软件创建“学生成绩管理系统”所需的数据库和表结构2. 数据库表设计包括学生信息表、课程信息表和成绩信息表 实现模型层代码1. 根据设计好的表结构,创…

    C 2023年5月23日
    00
  • C语言分支循环其嵌套语句的使用

    对于C语言程序,分支和循环结构都是非常重要的控制结构。它们可以让程序根据条件执行不同的操作,并可以利用循环结构让重复的操作更加简单和高效。 在实际编程中,分支和循环结构的嵌套使用能够更好地解决实际问题。下面我们分别讲解分支和循环在嵌套结构中的使用方法。 分支结构的嵌套使用 分支结构通常使用if / else或switch / case语句完成。分支结构的嵌套…

    C 2023年5月30日
    00
  • MathWorks MATLAB R2020b详细密钥安装教程(附许可下载)

    MathWorks MATLAB R2020b详细密钥安装教程(附许可下载) 简介 MathWorks MATLAB R2020b是一款流行的科学计算软件,广泛用于工程、科学和数学领域。为了使用MATLAB软件,需要先安装软件并激活许可证。 本篇文章将提供详细的步骤来完成MathWorks MATLAB R2020b的安装和许可证激活过程。此外,我们还会提供…

    C 2023年5月22日
    00
  • C++的静态类型检查详解

    C++的静态类型检查详解 C++是一门静态类型的编程语言,其中的静态类型检查是C++编译器能够在编译期间确定程序中变量类型的能力。这种特性提供了许多优点,例如类型安全和代码可读性,同时也有一些限制。 静态类型检查是什么 静态类型检查是指编译器在编译程序时,通过对程序的语法分析和类型推导,能够确定每个变量的类型和类型之间的关系。根据类型检查结果,编译器可以在编…

    C 2023年5月22日
    00
  • C#实现JSON解析器MojoUnityJson功能(简单且高效)

    C#实现JSON解析器MojoUnityJson功能(简单且高效) 简介 JSON格式是一种轻量级的数据交换格式,常用于web应用程序之间的数据传输,也广泛应用于移动应用程序的数据交互。MojoUnityJson是一款基于C#的JSON解析器,使用简单且高效。 实现过程 1. 定义数据类型 首先,我们需要定义一些数据类型,方便后续对JSON数据进行解析和处理…

    C 2023年5月23日
    00
  • C语言学生成绩管理系统源码

    C语言学生成绩管理系统源码完整攻略 源码下载 首先,我们需要从Github上下载C语言学生成绩管理系统的源代码。在Github上搜索关键词C语言学生成绩管理系统即可找到相应的项目。 下载完成后,我们可以得到以下几个文件: main.c:程序主函数 student.h:定义了student结构体以及相关函数的头文件 student.c:实现了student结构…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部