如何将此递归解决方案转换为记忆的解决方案,以解决最长的常见底带问题?
我能够自己提出递归解决方案,解决了最长的常见子字符串问题:
import static java.lang.Math.max;
public class SolutionRecursive {
public int longestCommonSubstringLength(String X, String Y) {
return lcsHelper(X, Y, 1, 1, 0);
}
private int lcsHelper(String X, String Y, int xSize, int ySize, int runningSubstringSize) {
if (xSize > X.length() || ySize > Y.length()) return runningSubstringSize;
if (X.charAt(xSize - 1) != Y.charAt(ySize - 1)) {
return max(runningSubstringSize,
max(lcsHelper(X, Y, xSize + 1, ySize, 0),
lcsHelper(X, Y, xSize, ySize + 1, 0)));
}
return lcsHelper(X, Y, xSize + 1, ySize + 1, runningSubstringSize + 1);
}
}
我对其进行了测试,而且似乎很好,但是我很难记住递归电话。
import java.util.Arrays;
public class SolutionMemoized implements SolutionLCS{
private final int UNFILLED = Integer.MIN_VALUE;
public int longestCommonSubstringLength(String X, String Y) {
int[][][] memo = new int[X.length() + 1][Y.length() + 1][X.length() + 1];
for (int i = 1; i < X.length() + 1; i++) {
for (int j = 0; j < Y.length() + 1; j++) {
Arrays.fill(memo[i][j], UNFILLED);
}
}
int lcs = lcsHelper(X, Y, X.length(), Y.length(), memo, 0);
return lcs;
}
private int lcsHelper(String X, String Y, int xSize, int ySize, int[][][] memo, int runningSubstringSize) {
if (xSize == 0 || ySize == 0) {
return runningSubstringSize;
}
if (memo[xSize][ySize][runningSubstringSize] != UNFILLED) {
return memo[xSize][ySize][runningSubstringSize];
}
if (X.charAt(xSize - 1) == Y.charAt(ySize - 1)) {
memo[xSize][ySize][runningSubstringSize] = lcsHelper(X, Y, xSize - 1, ySize - 1, memo,
runningSubstringSize + 1);
} else {
memo[xSize][ySize][runningSubstringSize] = Math.max(runningSubstringSize,
Math.max(
lcsHelper(X, Y, xSize - 1, ySize, memo, 0),
lcsHelper(X, Y, xSize, ySize - 1, memo, 0)
));
}
return memo[xSize][ySize][runningSubstringSize];
}
}
This apparently fails for longestCommonSubstringLength("KXCGMTMVVGFQQWSPD","JXZADDUKVLQPKUZJZHWSUTPCAFSYAIBJHAMMEGWBTPQELRNKBLDXGUZGCSEC")
for which the required answer is 2 but it gives 1. I couldn't find lower length failed tests.
谁能告诉我为什么不起作用?我觉得我的递归和回忆代码之间有清晰的1-1对应关系。
on youtube 我找到了一个修复程序,但作者没有解释他到达了。该修复程序将我的最后几行代码行更改为:
int s1 = runningSubstringSize;
if (X.charAt(xSize - 1) == Y.charAt(ySize - 1)) {
s1 = lcsHelper(X, Y, xSize - 1, ySize - 1, memo,
runningSubstringSize + 1);
}
int s2 = Math.max(runningSubstringSize,
Math.max(
lcsHelper(X, Y, xSize - 1, ySize, memo, 0),
lcsHelper(X, Y, xSize, ySize - 1, memo, 0)
));
return memo[xSize][ySize][runningSubstringSize] = Math.max(s1, s2);
为什么我的解决方案(代码块2)即使它与递归代码之间似乎有1-1对应关系?修复程序如何纠正它?
I was able to come up with the recursive solution to the longest common substring problem on my own:
import static java.lang.Math.max;
public class SolutionRecursive {
public int longestCommonSubstringLength(String X, String Y) {
return lcsHelper(X, Y, 1, 1, 0);
}
private int lcsHelper(String X, String Y, int xSize, int ySize, int runningSubstringSize) {
if (xSize > X.length() || ySize > Y.length()) return runningSubstringSize;
if (X.charAt(xSize - 1) != Y.charAt(ySize - 1)) {
return max(runningSubstringSize,
max(lcsHelper(X, Y, xSize + 1, ySize, 0),
lcsHelper(X, Y, xSize, ySize + 1, 0)));
}
return lcsHelper(X, Y, xSize + 1, ySize + 1, runningSubstringSize + 1);
}
}
I tested it and it seems to work fine but I am having trouble memoizing the recursive calls.
import java.util.Arrays;
public class SolutionMemoized implements SolutionLCS{
private final int UNFILLED = Integer.MIN_VALUE;
public int longestCommonSubstringLength(String X, String Y) {
int[][][] memo = new int[X.length() + 1][Y.length() + 1][X.length() + 1];
for (int i = 1; i < X.length() + 1; i++) {
for (int j = 0; j < Y.length() + 1; j++) {
Arrays.fill(memo[i][j], UNFILLED);
}
}
int lcs = lcsHelper(X, Y, X.length(), Y.length(), memo, 0);
return lcs;
}
private int lcsHelper(String X, String Y, int xSize, int ySize, int[][][] memo, int runningSubstringSize) {
if (xSize == 0 || ySize == 0) {
return runningSubstringSize;
}
if (memo[xSize][ySize][runningSubstringSize] != UNFILLED) {
return memo[xSize][ySize][runningSubstringSize];
}
if (X.charAt(xSize - 1) == Y.charAt(ySize - 1)) {
memo[xSize][ySize][runningSubstringSize] = lcsHelper(X, Y, xSize - 1, ySize - 1, memo,
runningSubstringSize + 1);
} else {
memo[xSize][ySize][runningSubstringSize] = Math.max(runningSubstringSize,
Math.max(
lcsHelper(X, Y, xSize - 1, ySize, memo, 0),
lcsHelper(X, Y, xSize, ySize - 1, memo, 0)
));
}
return memo[xSize][ySize][runningSubstringSize];
}
}
This apparently fails for longestCommonSubstringLength("KXCGMTMVVGFQQWSPD","JXZADDUKVLQPKUZJZHWSUTPCAFSYAIBJHAMMEGWBTPQELRNKBLDXGUZGCSEC")
for which the required answer is 2 but it gives 1. I couldn't find lower length failed tests.
Could anyone tell me why it doesn't work? I feel like there is clear 1-1 correspondence between my recursive and memoized codes.
On youtube I found a fix but the author didn't explain how he arrived at it. The fix is changing my last few lines of code to:
int s1 = runningSubstringSize;
if (X.charAt(xSize - 1) == Y.charAt(ySize - 1)) {
s1 = lcsHelper(X, Y, xSize - 1, ySize - 1, memo,
runningSubstringSize + 1);
}
int s2 = Math.max(runningSubstringSize,
Math.max(
lcsHelper(X, Y, xSize - 1, ySize, memo, 0),
lcsHelper(X, Y, xSize, ySize - 1, memo, 0)
));
return memo[xSize][ySize][runningSubstringSize] = Math.max(s1, s2);
Why doesn't my solution (code block 2) work even though there seems to be 1-1 correspondence between it and the recursive code? And how is the fix correcting it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您添加的修复程序已经使问题很明显:
如果当前字符相等,则贪婪地增加了
runningsubstringsize
,并为较小的字符串重复。示例:<代码>(ABDC,AFC)的解决方案简化为(ABD,AF) + 1 的解决方案。但是,您并不考虑仅减少一个字符串并检查它是否提供更好的解决方案的“正常”方案/流动。从上一个示例中,理想情况下应该是
添加的修复程序。在设置回忆表中的更新值之前,它会比较所有方案。
The fix you've added has made the issue evident:
If the current characters are equal, you greedily increase the
runningSubstringSize
and recurse for the smaller strings. Example:solution for (ABDC, AFC) reduced to solution for (ABD, AF) + 1
.However, you're not considering the "normal" scenario/flow of reducing only one string and checking if it gives a better solution. From the previous example, it should ideally be
The added fix does exactly that; it compares all scenarios before setting the updated value in the memoization table.