基于最长公共子序列思路的最长公共子串解法可行性问询
关于最长公共子串(LCSubstring)DP解法的问题解答
嘿,我来帮你理清楚这个问题~首先得先把子序列和子串的核心区别掰明白:
- 最长公共子序列(LCS):字符顺序一致,但不需要连续(比如
"abc"和"aec"的LCS是"ac") - 最长公共子串(LCSubstring):必须是连续的一段字符(比如
"abcde"和"abxde"的最长公共子串是"ab"或"de")
你的解法为什么不可行?
先看你写的最长公共子串递推逻辑:
if str1[i] != str2[j]: dp[i][j] = max(dp[i-1][j], dp[i][j-1]) else: if str1[i-1] == str2[j-1]: dp[i][j] = 1 + dp[i-1][j-1] else: dp[i][j] = 1 + dp[i-1][j-1]
这里有两个致命问题:
else里的判断完全没用——不管str1[i-1]和str2[j-1]是否相等,结果都是1 + dp[i-1][j-1],等于白写了这个条件- 最核心的错误:当
str1[i] != str2[j]时,你沿用了LCS的max(dp[i-1][j], dp[i][j-1])逻辑。但LCS的这个逻辑是为了保留之前不连续的最长匹配,而子串要求必须连续——一旦当前字符不匹配,当前位置的连续匹配就直接断裂了,根本不能继承之前的非连续结果。
正确的最长公共子串DP递推规则
我们重新定义dp[i][j]:以str1[i-1]和str2[j-1]结尾的最长公共子串的长度(这样处理边界更简单,当i=0或j=0时,dp[i][j] = 0,因为空字符串和任何字符串的公共子串长度都是0)。
递推规则如下:
- 如果
str1[i-1] == str2[j-1]:dp[i][j] = dp[i-1][j-1] + 1
(当前字符匹配,说明可以延续上一个位置的连续匹配长度) - 如果
str1[i-1] != str2[j-1]:dp[i][j] = 0
(当前字符不匹配,连续子串直接断裂,当前位置的连续长度归0)
另外要注意:我们需要在填充DP表的全过程中,记录所有dp[i][j]里的最大值,这个最大值就是最长公共子串的长度。
举个简单例子验证
比如str1 = "abcde",str2 = "abxde":
- 当
i=2, j=2(对应字符'b'和'b'):dp[2][2] = dp[1][1] + 1 = 2(前一个字符'a'也匹配,连续长度累加) - 当
i=3, j=3(对应字符'c'和'x'):dp[3][3] = 0(字符不匹配,连续断裂) - 当
i=5, j=5(对应字符'e'和'e'):dp[5][5] = dp[4][4] + 1 = 2(前一个字符'd'匹配,连续长度从1变成2)
最终DP表中的最大值是2,对应最长公共子串"ab"或"de",完全符合预期。
内容的提问来源于stack exchange,提问作者Bernerd
相关产品推荐
相关产品推荐

