📜  最长公共子串(空间优化DP方案)(1)

📅  最后修改于: 2023-12-03 15:10:37.396000             🧑  作者: Mango

最长公共子串(空间优化DP方案)

什么是最长公共子串?

最长公共子串(Longest Common Substring,简称 LCS)指的是两个字符串中,最长的有相同字串(即连续子串)的长度。

例如,字符串 A = "abcdefg",字符串 B = "defghij",它们的最长公共子串为 "def",长度为 3。

解决方案

我们可以使用动态规划(DP)来解决最长公共子串问题。但是,朴素的 DP 解法的空间复杂度较高,为 O(mn),其中 m 和 n 分别为两个字符串的长度。

在本文中,将介绍一种空间优化 DP 方案,其空间复杂度可降至 O(n)。

空间优化 DP

空间优化 DP 方案的核心思想是:在 DP 过程中,只需要记录当前计算所需的状态,而不需要记录所有的状态。

在 最长公共子序列 的空间优化 DP 方案中,我们只需记录上一个状态和当前状态,就能在 O(1) 空间内完成计算。但对于 最长公共子串,我们需要记录当前状态之前的状态,因为它们在计算当前状态时都会被用到。

我们可以借助滚动数组的思想,将二维数组优化为一维数组,并以一定的顺序依次计算出所有状态。具体来说,我们可以按行或按列的顺序计算状态,并将计算出的状态保存在一维数组中。这样,我们就只需要记录两个一维数组,即当前状态和前一个状态,就能完成整个 DP 过程,从而将空间复杂度降至 O(n)。

以下是最长公共子串的空间优化 DP 代码片段:

def longest_common_substring(s1: str, s2: str) -> int:
    m, n = len(s1), len(s2)
    dp = [0] * n  # 当前状态
    pre_dp = [0] * n  # 前一个状态
    max_len = 0
    for i in range(m):
        for j in range(n):
            if s1[i] == s2[j]:
                if i == 0 or j == 0:
                    dp[j] = 1  # 处理边界
                else:
                    dp[j] = pre_dp[j - 1] + 1  # 转移方程
                max_len = max(max_len, dp[j])
            else:
                dp[j] = 0  # 不匹配则置为0
            pre_dp[j] = dp[j]  # 更新前一个状态
    return max_len

在上述代码中,我们首先定义了两个一维数组:dppre_dp,分别代表当前状态和前一个状态。然后,我们按行的顺序依次计算状态,用 dp[j] 表示当前状态下以 s1[i] 和 s2[j] 结尾的最长公共子串的长度,用 pre_dp[j] 表示前一个状态下以 s1[i-1] 和 s2[j-1] 结尾的最长公共子串的长度。

对于每个状态 dp[j],如果 s1[i] 和 s2[j] 相等,则可以根据转移方程 dp[j] = pre_dp[j-1] + 1 计算出 dp[j];否则, dp[j] 应该为 0。每次计算完当前状态后,我们将 dp 数组保存为 pre_dp 数组,以备下一次计算使用。最终,我们遍历所有状态,找到最长的公共子串长度,并将其返回。

总结

空间优化 DP 方案通过记录当前状态和前一个状态,将二维数组优化为一维数组,并以一定的顺序依次计算出所有状态,从而将空间复杂度降至 O(n)。本文介绍了最长公共子串的空间优化 DP 方案,给出了对应的代码片段,并对其进行了解释。通过这种方案,我们可以在 O(n) 的空间复杂度下解决最长公共子串问题,从而为字符串匹配等问题的解决提供了更加高效简洁的解决方案。