找到2个字符串中最长的常见子序列?

时间:2016-05-13 01:10:16

标签: java arrays string dynamic-programming

我正在学习最长的常见子序列,使用这些算法:

cost table algorthm

enter image description here

公共类LCS {

static int[][] E;
static int[][] S;
static int D;
static int T;
static int L;
public static void LCS_cost(String X,String Y)
{       
    int m = X.length();
    int n = Y.length();
    E = new int[m][n];
    S = new int[m][n];
    for(int i=0;i<m;i++){
        E[i][0] = 0;
    }
    for(int j=0;j<n;j++){
        E[0][j] = 0;
    }
    for(int i=1;i<m+1;i++){
        for(int j=1;j<n+1;j++){
            if(X.charAt(i) == Y.charAt(j)){
                E[i][j] = E[i-1][j-1]+1;
                D =  E[i-1][j-1]+1;
                S[i][j] = D;//Diagonal Direction    
            }
            else if (E[i-1][j]>=E[i][j-1]){
                    E[i][j] = E[i-1][j];
                    T = E[i-1][j];
                    S[i][j] = T;//TOP
            }
            else
                    E[i][j] = E[i][j-1];
                    L = E[i][j-1];
                    S[i][j] = L;//Left
        }
    }

}

public static void Backtrack(int[][] S,String X,String Y){
int row = X.length();
int col = Y.length();   

while (row > 0 || col > 0){
    if (S[row][col] == D){
        System.out.print(X.charAt(row));
        row--;
        col--;
    }
    else if (S[row][col] == T){
        row--;
    }
    else
        col--;
}
}
public static void main(String[] args) {
    new  LCS();
    LCS_cost("SCHOOL","SPOOL");
    Backtrack(S,"SCHOOL", "SPOOL");
    }
}

但该程序返回ErrorCharAt(Unknow Source)并且没有做任何事情。

我正在尝试改变

for(int i=1;i<m+1;i++){
        for(int j=1;j<n+1;j++){

for(int i=1;i<m;i++){
        for(int j=1;j<n;j++){

结果就是这条线IndexOutofBoud

if (S[row][col] == D){
    ....
    }

另外,如果我将 int i j 更改为0,那么下面的E将是索引-1并且错误

for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            if(X.charAt(i) == Y.charAt(j)){
                E[i][j] = E[i-1][i-1]+1;
                ......
            }

我现在迷失了。任何人都可以帮助我吗?

4 个答案:

答案 0 :(得分:3)

我会使用字符串而不是处理单个字符来解决这个问题:

String findLCS(String str1, String str2) {
    int longest = 0;
    String longestSubstring = "";

    for (int i=0; i < str1.length(); ++i) {
        for (int j=i+1; j <= str1.length(); ++j) {
            String substring = str1.substring(i, j);
            if (str2.contains(substring) && substring.length() > longest) {
                longest = substring.length();
                longestSubstring = substring;
            }
        }
    }

    return longestSubstring;
}

正如您所看到的,使用String.contains()比看起来更强大。

答案 1 :(得分:0)

如果

 int m = X.length();

然后

for(int i=1;i<m+1;i++){
   ...
   if(X.charAt(i) ....

将抛出错误,因为Java数组是基于零的

如果

int row = X.length();
int col = Y.length(); 

if (S[row][col] == D){

会抛出错误

另外,使用String.equals来比较不是==

的字符串

答案 2 :(得分:0)

import java.util.Scanner; class Main {

public static void main(String[] args)
{


Scanner sc=new Scanner(System.in);




    Sub s=new Sub();

    int t=Integer.parseInt(sc.nextLine());

    for(int i=1;i<=t;i++)
    {




    String a=sc.next();
    String b=sc.next();

    System.out.println("Case "+i+": "+s.subString(a, b));


}

}

} class Sub {

   public static int subString (String a,String b)
   {

       int max=0;
       int m=a.length();
       int n=b.length();

       int dp[][]=new int [m][n];

       for(int i=0;i<m;i++)
       {

           for(int j=0;j<n;j++)
           {

               if(a.charAt(i)==b.charAt(j))

               {
                   if(i==0||j==0)
                   {
                       dp[i][j]=1;
                   }
                   else 
                       dp[i][j]=dp[i-1][j-1]+1;
               }

               if(max<dp[i][j])

                   max=dp[i][j];
           }


       }


       return max;

   }

}

答案 3 :(得分:0)

您使用的是矩阵方法,

  • 如果第[i]个字符和第[j]个字符匹配-沿对角线[i-1] [j-1]的值前进,并为lcs长度加1
  • 在第[i]个字符和第[j]个字符不匹配的情况下-对于lcs,取{left [i] [j-1]或right [i-1] [j]的最大值。

就我个人而言,我认为这种方法更具脚本性,而动态编程和记忆的本质却落伍了。当我们更依赖脚本方法而不是DP和备忘录的纯逻辑时-我们更容易出错,或者在这之间可能会迷路...

我不是使用矩阵方法,而是使用动态编程和备注来将LCS演示为-

package com.company.dynamicProgramming;

import java.util.HashMap;
import java.util.Map;

public class LongestCommonSubsequnce {


    public static void main(String ...args){

        String s1 = "SCHOOL";
        String s2 = "SPOOL";
        System.out.println(new StringBuilder(findLcs(s1, s2, new HashMap<>())).reverse());
    }



    static String findLcs(String s1, String s2, Map<String, String> memo){

        //check if lcs is already processed in memo for s1 & s2
        String lcs = memo.get(s1+"-"+s2);
        if(lcs != null){
            return lcs;
        }


        if (s1.substring(s1.length()-1).equals(s2.substring(s2.length()-1))){
            lcs = s1.substring(s1.length()-1);
            if(s1.length()>1 && s2.length()>1){
                lcs = lcs + findLcs(s1.substring(0, s1.length()-1), s2.substring(0, s2.length()-1), memo);
                memo.put(s1.substring(0, s1.length()-1)+ "-" + s2.substring(0, s2.length()-1), lcs);
            }
            else {
                memo.put(s1+"-"+s1, lcs);
            }
            return lcs;

        }else {

            String lcs1="";
            String lcs2="";

            if(s1.length()>1 && s2.length()>1){
                lcs1 = findLcs(s1.substring(0, s1.length()-1), s2, memo);
                memo.put(s1.substring(0, s1.length()-1)+"-"+s2, lcs1);
                lcs2 = findLcs(s1,s2.substring(0, s2.length()-1),memo);
                memo.put(s1 +"-"+s2.substring(0, s2.length()-1), lcs2);
            }
            else if(s1.length()>1){
                lcs1 = findLcs(s1.substring(0, s1.length()-1), s2, memo);
                memo.put(s1.substring(0, s1.length()-1)+"-"+s2, lcs1);
            }
            else if(s2.length()>1){
                lcs2 = findLcs(s1,s2.substring(0, s2.length()-1),memo);
                memo.put(s1 +"-"+s2.substring(0, s2.length()-1), lcs2);
            }else {
                memo.put(s1+"-"+s2,"");
            }

            if(lcs1.length() >= lcs2.length()){
                return lcs1;
            }else {
                return lcs2;
            }
        }
    }
}

运行此代码,结果为-

SOOL

Process finished with exit code 0