深入解析最长公共子串

深入解析最长公共子串

什么是最长公共子串

最长公共子串(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++关键字const的用法详解

    下面就是对“c++关键字const的用法详解”的完整攻略。 什么是const const 是 C++ 中的一个关键字,用来定义常量。在 C++ 中,常量是指不能被修改的值。 const的用法 1. 修饰变量 const 可以用来定义一个常量变量,被 const 修饰的变量一旦被初始化,就不能被修改。 示例代码: const int a = 10; 2. 修饰…

    C 2023年5月22日
    00
  • C语言实现链队列代码

    首先,我们需要了解链队列的定义和基本操作。 链队列是一种基于链表结构实现的队列,与普通队列相比,其主要不同点是使用链表来存储队列元素,所以不会存在队列溢出的情况。 链队列的基本操作包括: 初始化:创建一个空队列。 入队:在队列末尾插入一个元素。 出队:删除队首元素,并返回其值。 队列长度:返回队列中元素的个数。 遍历:依次访问队列中的每个元素。 下面是C语言…

    C 2023年5月23日
    00
  • PHP实现基于图的深度优先遍历输出1,2,3…n的全排列功能

    实现基于图的深度优先遍历并输出1,2,3…n的全排列功能可以分为以下几个步骤: 构建无向图 为了实现深度优先遍历,我们需要先构建一个无向图。对于1,2,3…n,我们可以将它们看成节点,而对于任意两个节点i和j,如果它们代表的数字的差的绝对值等于1,那么i和j之间就可以连一条边。这样,我们就可以得到一个无向图,方便后续的遍历操作。 实现深度优先遍历 深…

    C 2023年5月22日
    00
  • Win8.1系统在SSD盘安装双系统提示错误代码0xc0000225的故障原因及解决方法

    Win8.1系统在SSD盘安装双系统提示错误代码0xc0000225的故障原因及解决方法 故障原因 当我们在一个SSD盘上安装Win8.1系统的双系统时,有时会遇到以下错误提示: Windows 启动管理器 Windows 检测到计算机的启动配置数据(BCD)缺少必要的文件。 文件位于:»\Windows\system32\winload.efi 错误代码:…

    C 2023年5月24日
    00
  • IE浏览器打开异常0xco6d007f位置0x7c812fd3的解决办法

    IE浏览器打开异常0xco6d007f位置0x7c812fd3的解决办法 问题描述 在使用IE浏览器打开某些网站或者本地文件时,会出现以下错误提示:“应用程序无法正常启动,错误0xco6d007f,在应用程序的配置文件中出错,位置0x7c812fd3”。这种情况可能发生在不同的IE版本中,导致无法正常使用浏览器。 解决方案 以下是多种可能的解决方案,可以尝试…

    C 2023年5月23日
    00
  • C 运算符

    C 运算符是用于执行特定数学或逻辑操作的特殊符号。在程序中,使用这些运算符来计算表达式的值。下面是一些常用的 C 运算符: 算术运算符 加法运算符(+) 减法运算符(-) 乘法运算符(*) 除法运算符(/) 取模运算符(%) 这些算术运算符用于执行基本的数学运算。例如: int a = 10; int b = 20; int c = a + b; print…

    C 2023年5月10日
    00
  • C++ stringstream格式化输出输入详情

    C++ 的 stringstream 类是一个基于字符串的流,我们可以用它进行格式化输入和输出。在使用 stringstream 进行格式化输出时,可以通过设置类似 printf 函数的格式字符串来控制输出的格式。同时,在使用 stringstream 进行格式化输入时,我们可以根据一个给定的格式字符串来解析输入的字符串数据。接下来,我将详细介绍如何使用 C…

    C 2023年5月23日
    00
  • python集合类型用法分析

    Python集合类型用法分析 Python中的集合类型可用于存储一组无序且不重复的元素。本篇攻略将详细讲解Python中常用的集合类型及其用法。 集合类型 Python中常用的集合类型有三种: set frozenset dict 其中,set和frozenset是用来存储一组无序且不重复的元素的,而dict则是用来存储键值对的。 set类型 set类型使用…

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