Recursion 使用递归和DP的最长公共子串
我正在尝试使用递归和DP查找两个字符串中最长的公共子字符串。请注意,我不是指最长的连续子序列。那么,如果这两个字符串是Recursion 使用递归和DP的最长公共子串,recursion,dynamic-programming,backtracking,longest-substring,recursive-backtracking,Recursion,Dynamic Programming,Backtracking,Longest Substring,Recursive Backtracking,我正在尝试使用递归和DP查找两个字符串中最长的公共子字符串。请注意,我不是指最长的连续子序列。那么,如果这两个字符串是 String s1 = "abcdf"; String s2 = "bzcdf" Longest Common Substring == "cdf" (not "bcdf"). Basically they have to be continuous elements 我尝试使用递归和回溯来实现这一点。然而,问题是,如果我使用下面这样的递归,+1被预先添加到一个帧中,该帧在
String s1 = "abcdf"; String s2 = "bzcdf"
Longest Common Substring == "cdf" (not "bcdf").
Basically they have to be continuous elements
我尝试使用递归和回溯来实现这一点。然而,问题是,如果我使用下面这样的递归,+1被预先添加到一个帧中,该帧在调用堆栈中处于较高的位置,并且不知道将要出现的字符是否确实是连续元素。因此,通过上面的示例,bcdf将是答案
public class ThisIsLongestCommonSubsequence_NotSubstring {
public static void main(String[] args) {
String s1 = "abcdgh";
String s2 = "abefgh";
System.out.println(fun(s1, s1.length()-1, s2, s2.length()-1));
}
static int fun(String s1, int i, String s2, int j)
{
if(i == -1 || j == -1)
return 0;
int ret = 0;
if(s1.charAt(i) == s2.charAt(j))
ret = fun(s1, i-1, s2, j-1) + 1;
else
ret = max(fun(s1, i-1, s2, j), fun(s1, i, s2, j-1));
return ret;
}
static int max(int a, int b)
{
return a>b?a:b;
}
}
至于现在,下面的代码就是我想到的。请注意,每次发现不匹配时,我都会将计数重置为0。并使用一个名为int count的变量跟踪匹配字符的数量,并使用一个名为int maxcount的变量记录程序中任意点的最大值。下面是我的代码
public class LongestContinuousSubstringGlobalvariable {
static int maxcount = 0;
public static void main(String[] args) {
String s1 = "abcdghijl";
String s2 = "abefghijk";
fun(s1, s2, s1.length()-1, s2.length()-1, 0);
System.out.println("maxcount == "+maxcount);
}
static void fun(String s1, String s2, int i, int j, int count)
{
if(i == -1 || j==-1)
return;
if(s1.charAt(i) == s2.charAt(j))
{
if(count+1 > maxcount)
maxcount = count+1;
fun(s1, s2, i-1, j-1, count+1);
}
else
{
fun(s1, s2, i-1, j, 0);
fun(s1, s2, i, j-1, 0);
}
}
}
这个很好用。然而,我的代码中有几点我不喜欢
使用全局变量static int maxcount跨帧比较
我不认为这是真正的动态规划或回溯,因为较低的帧不会将其输出返回到较高的帧,而较高的帧决定如何处理它。
请给出您的意见,说明如何在不使用全局变量和回溯的情况下实现这一点
PS:我知道解决这个问题的其他方法,比如保持矩阵,做类似的事情
M[i][j]=M[i-1][j-1]+1ifstr[i]==str[j]
我们的目标不是解决问题,而是找到一个优雅的递归/回溯解决方案。这可能可以在Prolog中完成。下面是我可以在这篇文章的帮助下写下的代码:,和 它运行时显示了所有步骤:将字符串转换为代码,然后从这两个字符串中生成所有可能的子字符串,然后找到常见的子字符串并列出它们:
?- myrun("abcdf", "bzcdf").
-------- codes of first string ---------
[97,98,99,100,102]
-------- codes of second string ---------
[98,122,99,100,102]
--------- substrings of first --------
[[],[97],[97,98],[97,98,99],[97,98,99,100],[97,98,99,100,102],[],[98],[98,99],[98,99,100],[98,99,100,102],[],[99],[99,100],[99,100,102],[],[100],[100,102],[],[102],[]]
--------- substrings of second --------
[[],[98],[98,122],[98,122,99],[98,122,99,100],[98,122,99,100,102],[],[122],[122,99],[122,99,100],[122,99,100,102],[],[99],[99,100],[99,100,102],[],[100],[100,102],[],[102],[]]
------ codes of common substrings -------
[[],[],[98],[],[99],[99,100],[99,100,102],[],[100],[100,102],[],[102],[]]
--------- common strings in one line -------
[,,b,,c,cd,cdf,,d,df,,f,]
------ common strings one by one -------
b
c
cd
cdf
d
df
f
------ find longest -------
[99,100,102]
cdf
true.
忽略结尾处的“true”
如果删除了说明部分,则程序要短得多:
myrun(S1, S2):-
string_codes(S1, C1list),
string_codes(S2, C2list),
findall(X, sublist(X, C1list), L),
findall(X, sublist(X, C2list), M),
intersection(L,M, Outl),
longest(Outl, LongestL),
string_codes(LongestS, LongestL),
writeln(LongestS).
sublist(S, L) :-
append(_, L2, L),
append(S, _, L2).
longest([L], L) :-
!.
longest([H|T], H) :-
length(H, N),
longest(T, X),
length(X, M),
N > M,
!.
longest([H|T], X) :-
longest(T, X),
!.
?- myrun("abcdf", "bzcdf").
cdf
true.
可能重复的
myrun(S1, S2):-
string_codes(S1, C1list),
string_codes(S2, C2list),
findall(X, sublist(X, C1list), L),
findall(X, sublist(X, C2list), M),
intersection(L,M, Outl),
longest(Outl, LongestL),
string_codes(LongestS, LongestL),
writeln(LongestS).
sublist(S, L) :-
append(_, L2, L),
append(S, _, L2).
longest([L], L) :-
!.
longest([H|T], H) :-
length(H, N),
longest(T, X),
length(X, M),
N > M,
!.
longest([H|T], X) :-
longest(T, X),
!.
?- myrun("abcdf", "bzcdf").
cdf
true.