Java 所有最长公共子序列

Java 所有最长公共子序列,java,lcs,Java,Lcs,[注意:我事先搜索过,找不到解决所有子序列LCS问题的建议。] 我在编写最长公共子序列问题的解决方案时遇到了困难,因为我返回了两个输入字符串的所有最长公共子序列。我查看了,并尝试在那里实现伪代码,但我的backtrackAll方法遇到了问题。我相信我在下面正确地计算了LCS矩阵,但是我的backtrackAll方法返回一个空集。有关于我做错了什么的提示吗 public static void main (String[] args) { String s1 = "AGCAT";

[注意:我事先搜索过,找不到解决所有子序列LCS问题的建议。]

我在编写最长公共子序列问题的解决方案时遇到了困难,因为我返回了两个输入字符串的所有最长公共子序列。我查看了,并尝试在那里实现伪代码,但我的backtrackAll方法遇到了问题。我相信我在下面正确地计算了LCS矩阵,但是我的backtrackAll方法返回一个空集。有关于我做错了什么的提示吗

public static void main (String[] args) {
    String s1 = "AGCAT";
    String s2 = "GAC";
    int[][] matrix = computeMatrix(s1,s2);
    HashSet<String> set = backtrackAll(matrix,s1,s2,s1.length(),s2.length());
    //more stuff would go here...
}

private static int[][] computeMatrix(String s1, String s2) {
    int[][] C = new int[s1.length()+1][s2.length()+1];
    for (int i = 1; i < s1.length()+1; i++) {
        for (int j = 1; j < s2.length()+1; j++) {
            if (s1.charAt(i-1) == s2.charAt(j-1)) {
                C[i][j] = C[i-1][j-1] + 1;
            } else {
                C[i][j] = Math.max(C[i][j-1], C[i-1][j]);
            }
        }
    }
    return C;
}

private static HashSet<String> backtrackAll(int[][] C, String s1, String s2, int i, int j) {
    if (i == 0 || j == 0) {
        return new HashSet<String>();
    } else if (s1.charAt(i-1) == s2.charAt(j-1)) {
        HashSet<String> R = backtrackAll(C,s1,s2,i-1,j-1);
        HashSet<String> new_set = new HashSet<String>();
        for (String Z: R) {
            new_set.add(Z + s1.charAt(i-1));
        }
        return new_set;
    } else {
        HashSet<String> R = new HashSet<String>();
        if (C[i][j-1] >= C[i-1][j]) {
            R = backtrackAll(C, s1, s2, i, j-1);
        } 
        if (C[i-1][j] >= C[i][j-1]) {
            R.addAll(backtrackAll(C,s1,s2,i-1,j));
        }
        return R;
    }
}

因为这是家庭作业,这里有几个提示

确保您理解所编写的算法。这可能是找出实现中的错误的最重要的一步

尝试使用调试器找出发生了什么。比较你认为应该发生的事情和实际发生的事情

尝试向代码中添加一些断言语句,以检查您认为应该为真的前提条件、后置条件和不变量。使用java-ea运行

坚持正常的Java命名约定。变量名以小写字母开头。变量名中没有下划线


因为这是家庭作业,这里有几个提示

确保您理解所编写的算法。这可能是找出实现中的错误的最重要的一步

尝试使用调试器找出发生了什么。比较你认为应该发生的事情和实际发生的事情

尝试向代码中添加一些断言语句,以检查您认为应该为真的前提条件、后置条件和不变量。使用java-ea运行

坚持正常的Java命名约定。变量名以小写字母开头。变量名中没有下划线


我稍微修改了一下。它现在起作用了。还应该考虑何时返回空哈希集,在该情况下,必须添加最后匹配的字符。

private static HashSet<String> backtrackAll(int[][] C, String s1, String s2, int i, int j) {
    // System.out.println(i+" " + j);
    if (i == 0 || j == 0) {
        // System.out.println("0t");
        return new HashSet<String>();
    } else if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
        // System.out.println("2t");
        HashSet<String> R = backtrackAll(C, s1, s2, i - 1, j - 1);
        HashSet<String> new_set = new HashSet<String>();

        for (String Z : R) {
            // System.out.println("1t");
            new_set.add(Z + s1.charAt(i - 1));
        }
        new_set.add("" + s1.charAt(i - 1));
        return new_set;
    } else {
        // System.out.println("3t");
        HashSet<String> R = new HashSet<String>();
        if (C[i][j - 1] >= C[i - 1][j]) {
            R = backtrackAll(C, s1, s2, i, j - 1);
        }
        if (C[i - 1][j] >= C[i][j - 1]) {
            R.addAll(backtrackAll(C, s1, s2, i - 1, j));
        }
        return R;
    }
}

我稍微修改了一下。它现在起作用了。还应该考虑何时返回空哈希集,在该情况下,必须添加最后匹配的字符。

private static HashSet<String> backtrackAll(int[][] C, String s1, String s2, int i, int j) {
    // System.out.println(i+" " + j);
    if (i == 0 || j == 0) {
        // System.out.println("0t");
        return new HashSet<String>();
    } else if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
        // System.out.println("2t");
        HashSet<String> R = backtrackAll(C, s1, s2, i - 1, j - 1);
        HashSet<String> new_set = new HashSet<String>();

        for (String Z : R) {
            // System.out.println("1t");
            new_set.add(Z + s1.charAt(i - 1));
        }
        new_set.add("" + s1.charAt(i - 1));
        return new_set;
    } else {
        // System.out.println("3t");
        HashSet<String> R = new HashSet<String>();
        if (C[i][j - 1] >= C[i - 1][j]) {
            R = backtrackAll(C, s1, s2, i, j - 1);
        }
        if (C[i - 1][j] >= C[i][j - 1]) {
            R.addAll(backtrackAll(C, s1, s2, i - 1, j));
        }
        return R;
    }
}

第二个答案打印所有内容,但不只是最长的,我的答案是正确的

private static HashSet<String> backtrackAll(int[][] C, String s1, String s2, int i, int j) {
    if (i == 0 || j == 0) {
        HashSet<String> set = new HashSet<String>();
        set.add("");
        return set;

    } else if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
        HashSet<String> R = backtrackAll(C, s1, s2, i - 1, j - 1);
        HashSet<String> new_set = new HashSet<String>();

        for (String Z : R) {
            new_set.add(Z + s1.charAt(i - 1));
        }
        return new_set;
    } else {
        HashSet<String> R = new HashSet<String>();
        if (C[i][j - 1] >= C[i - 1][j]) {
            R = backtrackAll(C, s1, s2, i, j - 1);
        }
        if (C[i - 1][j] >= C[i][j - 1]) {
            R.addAll(backtrackAll(C, s1, s2, i - 1, j));
        }
        return R;
    }
}

第二个答案打印所有内容,但不只是最长的,我的答案是正确的

private static HashSet<String> backtrackAll(int[][] C, String s1, String s2, int i, int j) {
    if (i == 0 || j == 0) {
        HashSet<String> set = new HashSet<String>();
        set.add("");
        return set;

    } else if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
        HashSet<String> R = backtrackAll(C, s1, s2, i - 1, j - 1);
        HashSet<String> new_set = new HashSet<String>();

        for (String Z : R) {
            new_set.add(Z + s1.charAt(i - 1));
        }
        return new_set;
    } else {
        HashSet<String> R = new HashSet<String>();
        if (C[i][j - 1] >= C[i - 1][j]) {
            R = backtrackAll(C, s1, s2, i, j - 1);
        }
        if (C[i - 1][j] >= C[i][j - 1]) {
            R.addAll(backtrackAll(C, s1, s2, i - 1, j));
        }
        return R;
    }
}

以下是C语言中的两个版本,用于获取您可能引用的最长公共子序列:

基于包含最长公共子序列长度的缓存表的回溯

在缓存时,不是缓存,而是捕获lcs本身

基于前缀lcs长度的版本1回溯:

**其中递归函数的调用方是**

string[] GetLongestCommonSubsequences(string A, string B, int[][] DP_LCS_AllPrefixes_Cache)
        {
            var r = this.GetLongestCommonSubsequences(A, B, A.Length, B.Length,
                DP_LCS_AllPrefixes_Cache);
            return r;
        }
版本2-缓存捕获所有前缀的lcs


以下是C语言中的两个版本,用于获取您可能引用的最长公共子序列:

基于包含最长公共子序列长度的缓存表的回溯

在缓存时,不是缓存,而是捕获lcs本身

基于前缀lcs长度的版本1回溯:

**其中递归函数的调用方是**

string[] GetLongestCommonSubsequences(string A, string B, int[][] DP_LCS_AllPrefixes_Cache)
        {
            var r = this.GetLongestCommonSubsequences(A, B, A.Length, B.Length,
                DP_LCS_AllPrefixes_Cache);
            return r;
        }
版本2-缓存捕获所有前缀的lcs