0

私は、再帰とDPを使用して2つの文字列の最長共通部分文字列を見つけようとしています。私は、最も長い連続サブシーケンスを指しているわけではないことに注意してください。したがって、2つの文字列がある場合再帰とDPを使用する最も長い共通部分文字列

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 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); 
    } 
} 
} 

これは問題なく動作します。しかし、物事のカップルは、私が

  1. グローバル変数(静的int型MAXCOUNT)の使用は、フレームにわたって
  2. 私は、これは本当の動的プログラミングや後戻りはないと思います比較することが私のコードについては好きではありませんがあります下側のフレームはを返すではないので、上位のフレームに出力されます。上位のフレームは、それをどう処理するかを決定します。

グローバル変数を使用せずに、バックトラッキングを使用してこれを達成する方法について私にあなたの入力をお願いします。

PS:私は行列を維持するように、この問題に対する他のアプローチを認識していて、

M [i]の[J] = M [I-1]〜[J-1]のようなものをやって+1 if(str [i] == str [j])

目的は、問題を解決するのではなく、エレガントな再帰/バックトラッキングソリューションを見つけることです。

+0

[最長共通部分](http://stackoverflow.com/questions/22319437/longest-common-substring)の可能性の重複 – Prune

答えて

-1

おそらくPrologで行うことができます。続いて、私はこのポストから助けを借りて置くことができたコードです:すべてのステップを示すそれを実行Foreach not working in Prologhttp://obvcode.blogspot.in/2008/11/working-with-strings-in-prolog.htmlHow do I find the longest list in a list of lists?

myrun(S1, S2):- 
    writeln("-------- codes of first string ---------"), 
    string_codes(S1, C1list), 
    writeln(C1list), 

    writeln("-------- codes of second string ---------"), 
    string_codes(S2, C2list), 
    writeln(C2list), 

    writeln("--------- substrings of first --------"), 
    findall(X, sublist(X, C1list), L), 
    writeln(L), 

    writeln("--------- substrings of second --------"), 
    findall(X, sublist(X, C2list), M), 
    writeln(M), 

    writeln("------ codes of common substrings -------"), 
    intersection(L,M, Outl), 
    writeln(Outl), 

    writeln("--------- common strings in one line -------"), 
    maplist(string_codes, Sl, Outl), 
    writeln(Sl), 
    writeln("------ common strings one by one -------"), 
    maplist(writeln, Sl), 

    writeln("------ find longest -------"), 
    longest(Outl, LongestL), 
    writeln(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"). 
-------- 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. 
関連する問題