动态规划——最长公共子串:理解空间优化
Posted
技术标签:
【中文标题】动态规划——最长公共子串:理解空间优化【英文标题】:Dynamic programming--Longest Common Substring: Understanding the space optimization 【发布时间】:2020-08-13 07:41:24 【问题描述】:我正在解决一个非常典型的问题,即两个字符串的最长公共子字符串。 问题陈述很清楚: 对于两个字符串 s1 和 s2,找出它们最长的公共子串的长度。 我可以理解dp数组所代表的状态的定义。它是一个二维数组,其中二维仅表示每个字符串中字符的索引(但仅基于 1 而不是基于 0)。 原始解决方案代码如下所示,对我来说很清楚:
public int findLCSLength(String s1, String s2)
int[][] dp = new int[s1.length()+1][s2.length()+1];
int maxLength = 0;
for(int i=1; i <= s1.length(); i++)
for(int j=1; j <= s2.length(); j++)
if(s1.charAt(i-1) == s2.charAt(j-1))
dp[i][j] = 1 + dp[i-1][j-1];
maxLength = Math.max(maxLength, dp[i][j]);
return maxLength;
这个解决方案显然可以优化,因为 dp[i][j] 的状态只取决于前一行,这意味着两行对于 dp 数组就足够了。 所以我把dp数组做成二维的,用mod操作映射2范围内的索引。
static int findLCSLength(String s1, String s2)
int[][] dp = new int[2][s2.length()+1];
int maxLength = 0;
for(int i=1; i <= s1.length(); i++)
for(int j=1; j <= s2.length(); j++)
if(s1.charAt(i-1) == s2.charAt(j-1))
dp[i%2][j] = 1 + dp[(i-1)%2][j-1];
maxLength = Math.max(maxLength, dp[i%2][j]);
return maxLength;
但是我的代码并没有为所有测试用例生成正确的答案。我找到了一个代码 sn-p,它在所有测试用例上都给出了正确的答案,而我错过了只有一个额外的操作。
static int findLCSLength(String s1, String s2)
int[][] dp = new int[2][s2.length()+1];
int maxLength = 0;
for(int i=1; i <= s1.length(); i++)
for(int j=1; j <= s2.length(); j++)
//This is the only extra line I missed
dp[i%2][j] = 0;
if(s1.charAt(i-1) == s2.charAt(j-1))
dp[i%2][j] = 1 + dp[(i-1)%2][j-1];
maxLength = Math.max(maxLength, dp[i%2][j]);
return maxLength;
我的代码失败的情况之一是“passport”和“ppsspt”,其中我的代码生成了 4,但正确答案显然是 3。 我很困惑,但是这条线,这条线做什么以及为什么有必要? 希望任何人都可以提供帮助。
【问题讨论】:
【参考方案1】:它重置当前计数。
您的代码在以下情况下设置此变量:
if(s1.charAt(i-1) == s2.charAt(j-1))
但没有其他方法可以将其设置为 0,这实际上是该代码所做的。
所以考虑什么时候:
s1.charAt(i-1) != s2.charAt(j-1)
您在此数组位置中的前一个值将在不应该的情况下延续到下一个子字符串比较。
【讨论】:
以上是关于动态规划——最长公共子串:理解空间优化的主要内容,如果未能解决你的问题,请参考以下文章