0

I just finished a program which enable to report all possible LCS and the location of the two strings respectively. However, the output of the test case isn't totally correct.

For example, if the two strings are "AACADBCDADCB" and "DCACDCBBDBAD", the correct result should report 8 cases. My output just report 6 cases, like below:

--- Output --- Max. length = 7
LCS: ACDBDAD , in X: 2 3 5 6 8 9 10 , in Y: 3 4 5 7 9 11 12
LCS: ACDBDAD , in X: 2 3 5 6 8 9 10 , in Y: 3 4 5 8 9 11 12
LCS: ACDCDAD , in X: 2 3 5 7 8 9 10 , in Y: 3 4 5 6 9 11 12
LCS: CADBDAD , in X: 3 4 5 6 8 9 10 , in Y: 2 3 5 7 9 11 12
LCS: CADBDAD , in X: 3 4 5 6 8 9 10 , in Y: 2 3 5 8 9 11 12
LCS: CADCDAD , in X: 3 4 5 7 8 9 10 , in Y: 2 3 5 6 9 11 12

Please give me some suggestions. Pretty Thanks!

import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;

public class LCSMain {

//test case
private static String x = "AACADBCDADCB";
private static String y = "DCACDCBBDBAD";

private static int maxLength = 0;
private static List<String> maxNodelist = new ArrayList<String>();
private static int[][] len =  null;
private static int[][] type = null;
private static TreeSet<String> outputSet = new TreeSet<String>();

public static void main (String[] args) {

    len = new int[x.length()+1][y.length()+1];
    type = new int[x.length()+1][y.length()+1];
    dpMatrix(x,y);

    //Backtrack all possible LCS and add the results into outputSet
    for(int count=0; count< maxNodelist.size(); count++){

        String index = maxNodelist.get(count);
        String[] indexAry = index.split(",");
        int i = Integer.valueOf(indexAry[0]);
        int j = Integer.valueOf(indexAry[1]);
        ArrayList<ArrayList<String>> list = backTrack(x, y, i, j);

        for(int counter=0; counter<list.get(0).size(); counter++){
            outputSet.add(list.get(0).get(counter) +"," + list.get(1).get(counter)  + "," + list.get(2).get(counter));
        }  
    }

    //Print all possible results
    System.out.println("--- Output ---");
    System.out.println("Max. length = " + len[x.length()][y.length()]);
    for(String s: outputSet){
        String[] ary = s.split(",");
        System.out.println("LCS: " + ary[0] + " , in X: " + ary[1]  + " , in Y: " + ary[2]);            
    }

}

/**
* Set the DP matrix
**/
private static void dpMatrix(String s1, String s2) {

    for (int i = 1; i <=s1.length(); i++) {         
        for (int j = 1; j <=s2.length(); j++) {

            if (s1.charAt(i-1) == s2.charAt(j-1)) {                 

                len[i][j] = len[i-1][j-1] + 1;                  
                type[i][j] = 1;

            }else{

                if(len[i-1][j] != len[i][j-1]){

                    if(len[i-1][j] > len[i][j-1]){                          
                        len[i][j] = len[i-1][j];
                        type[i][j] = 2;                         
                    }else{                          
                        len[i][j] = len[i][j-1];
                        type[i][j] = 3;                     
                    }                   

                }else{
                    //if equal, set is as case 4
                    len[i][j] = len[i][j-1];
                    type[i][j] = 4;                     
                }

            }

            if(len[i][j] > maxLength){
                maxNodelist.clear();
                maxLength = len[i][j];
                maxNodelist.add(i + "," + j);
            }else if(len[i][j] == maxLength){
                maxNodelist.add(i + "," + j);
            }   

        }// End of for

    }// End of for

}   

/**
 * Backtrack from (i, j). Find out LCS and record the location of the strings respectively
 * @param s1 1st string
 * @param s2 2nd string
 * @param i row index in the matrix
 * @param j column index in the matrix
 * @return ArrayList<ArrayList<String>>, outer ArrayList collect three inner ArrayList in order: LCS string, 1st string LCS location, 2nd string LCS location
 */
private static ArrayList<ArrayList<String>> backTrack(String s1, String s2, int i, int j){

       if (i == 0 || j == 0) {
            ArrayList<ArrayList<String>> list = new ArrayList<ArrayList<String>>();
            ArrayList<String> lcsList = new ArrayList<String>();
            ArrayList<String> xList = new ArrayList<String>();
            ArrayList<String> yList = new ArrayList<String>();
            lcsList.add("");
            xList.add("");
            yList.add("");
            list.add(lcsList);
            list.add(xList);
            list.add(yList);

            return list;
        }

        if(type[i][j]==1){

            ArrayList<ArrayList<String>> resultList = new ArrayList<ArrayList<String>>();
            ArrayList<String> resultLcsList = new ArrayList<String>();
            ArrayList<String> resultXList = new ArrayList<String>();
            ArrayList<String> resultYList = new ArrayList<String>();

            ArrayList<ArrayList<String>> list = backTrack(s1, s2, i - 1, j - 1);

            ArrayList<String> lcsList = list.get(0);
            ArrayList<String> xList = list.get(1);
            ArrayList<String> yList = list.get(2);
            for(String s: lcsList){
                resultLcsList.add(s + s1.charAt(i - 1));                    
            }
            for(String s: xList){
                resultXList.add(s + " " + i);
            }
            for(String s: yList){
                resultYList.add(s + " " + j);
            }

            resultList.add(resultLcsList);
            resultList.add(resultXList);
            resultList.add(resultYList);

            return resultList;

        }else if(type[i][j]==2){

            ArrayList<ArrayList<String>> list = backTrack(s1,s2, i-1, j);
            return list;

        }else if(type[i][j]==3){

            ArrayList<ArrayList<String>> list = backTrack(s1,s2, i, j-1);
            return list;

        }else{

            ArrayList<ArrayList<String>> list = new ArrayList<ArrayList<String>>();
            list = backTrack(s1,s2, i-1, j);
            ArrayList<ArrayList<String>> case3list = backTrack(s1,s2, i, j-1);

            ArrayList<String> lcsList = list.get(0);
            ArrayList<String> xList = list.get(1);
            ArrayList<String> yList = list.get(2);
            lcsList.addAll(case3list.get(0));
            xList.addAll(case3list.get(1));
            yList.addAll(case3list.get(2));
            list.set(0, lcsList);
            list.set(1, xList);
            list.set(2, yList);

            return list;

        }

    }

}
  • This should be put in CodeReview instead of being here. – justhalf Nov 26 '13 at 07:18
  • @justhalf: CodeReview is for correct and working code. I agree though that some more preparation needs to be put into this question, otherwise I don't see how this should be getting a good answer. – Niklas B. Nov 26 '13 at 14:28

1 Answers1

0

I've updated your code to visualize the snakes (path of the LCS found), to use the interface type of List instead of the concrete object ArrayList and gave the direction values a bit more meaning by utilizing an enumeration instead of an int value.

It may not be the best code I've ever written but it does the job of visualizing the snakes found:

package lcs;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;

/**
 * <p>
 * Longest common subsequecne finds the longest subsequence common to all 
 * sequences in a set of sequences. A subsequence in contrast to a substring
 * does not have to consist of consecutive terms.
 * </p>
 */
public class LCSMain 
{
    //test case
    private static String x = "AACADBCDADCB";
    private static String y = "DCACDCBBDBAD";

    /** The maximum length of the longest common subsequences found **/
    private static int maxLength = 0;
    /** will hold a reference to the (i,j) nodes with match the length of the
     * longest common subsequence **/
    private static List<String> maxNodelist = new ArrayList<>();
    /** will hold a form of heightfield that indicates the length of a 
     * subsequence which is reachable from this position **/
    private static int[][] len =  null;
    /** will hold the direction values to backtrack the longest common 
     * subsequences **/
    private static Direction[][] type = null;
    private static TreeSet<String> outputSet = new TreeSet<>();

    /**
     * <p>
     * Entrance point for the application. It will find the longest common 
     * subsequences (LCS) between <em>AACADBCDADCB</em> and <em>DCACDCBBDBAD</em>
     * and print a graphical representation of the snakes (=path for a LCS) found
     * as well as a listing of the found LCS and their positions within the
     * original strings.
     * </p>
     * 
     * @param args The arguments passed to the application. Unused.
     */
    public static void main (String[] args) 
    {
        len = new int[x.length()+1][y.length()+1];
        type = new Direction[x.length()+1][y.length()+1];
        dpMatrix(x,y);

        //Backtrack all possible LCS and add the results into outputSet
        for(int count=0; count< maxNodelist.size(); count++)
        {
            String index = maxNodelist.get(count);
            String[] indexAry = index.split(",");
            int i = Integer.valueOf(indexAry[0]);
            int j = Integer.valueOf(indexAry[1]);
            List<List<String>> list = backTrack(x, y, i, j);

            for(int counter=0; counter<list.get(0).size(); counter++)
            {
                outputSet.add(list.get(0).get(counter) +"," 
                    + list.get(1).get(counter)  + "," 
                    + list.get(2).get(counter));
            }  
        }
        // visualize the maximum length of a longest common subsequence
        // accessible from any point in the matrix
        printHeightField();
        // visualize the path's found for the longest common subsequences
        printSnake();

        //Print all possible results
        System.out.println("--- Output ---");
        System.out.println("Max. length = " + len[x.length()][y.length()]);
        for(String s: outputSet)
        {
            String[] ary = s.split(",");
            System.out.println("LCS: " + ary[0] + ", in X: " 
                + ary[1]  + ", in Y: " + ary[2]);            
        }
    }

    /**
     * <p>
     * Prints the different subsequences into a matrix which contains the 
     * calculated direction values.
     * </p>
     */
    private static void printSnake()
    {
        // fill a char matrix with direction values
        char[][] matrix = createDirectionMatrix();

        // add path information to the matrix
        for (String node : maxNodelist)
        {
            String[] indexAry = node.split(",");
            int i = Integer.valueOf(indexAry[0]);
            int j = Integer.valueOf(indexAry[1]);

            backtrackPath(matrix, i, j);
        }

        // print the matrix
        System.out.println("Snakes:");
        System.out.println(printMatrix(matrix));
    }

    /**
     * <p>
     * Adds backtracking information to the direction matrix.
     * </p>
     * 
     * @param matrix The matrix to update with path informations
     * @param i row index in the type matrix
     * @param j column index in the type matrix
     */
    private static void backtrackPath(char[][] matrix, int i, int j)
    {
        if (i==0 || j==0)
            return;

        // convert the index to matrix coordinates
        int line = j*2+2;
        int col = i*2+3;
        // check which direction we need to follow
        if (Direction.EQUALS.equals(type[i][j]))
        {
            matrix[line-1][col-1] = '\\';
            backtrackPath(matrix, i-1, j-1);
        }
        else if (Direction.LEFT.equals(type[i][j]))
        {
            matrix[line][col-1] = '-';
            backtrackPath(matrix, i-1, j);
        }
        else if (Direction.TOP.equals(type[i][j]))
        {
            matrix[line-1][col] = '|';
            backtrackPath(matrix, i, j-1);
        }
        else
        {
            // split the path in both direction: to the left and to the top
            matrix[line][col-1] = '-';
            backtrackPath(matrix, i-1, j);

            matrix[line-1][col] = '|';
            backtrackPath(matrix, i, j-1);
        }
    }

    /**
     * <p>
     * Creates an output matrix for the specified words containing the direction
     * values as matrix data.
     * </p>
     * 
     * @return The created matrix containing direction values for the longest 
     *         common subsequences
     */
    private static char[][] createDirectionMatrix()
    {
        char[][] matrix = new char[2+type.length*2-1][];
        for (int i=0; i<matrix.length; i++)
            matrix[i] = new char[2+type.length*2];

        // build the output matrix
        for (int line=0; line<matrix.length; line++)
        {
            // The header column
            if (line == 0)
            {
                for (int col = 0; col < matrix[line].length; col++)
                {
                    if (col == 3)
                        matrix[line][col] = '^';
                    else if (col == 1)
                        matrix[line][col] = '|';
                    // empty column
                    else if (col % 2 == 0)
                        matrix[line][col] = ' ';
                    else if (col > 4)
                    {
                        matrix[line][col] = x.charAt(col / 2 - 2);
                    }
                } 
            }
            else if (line == 1)
            {
                for (int col = 0; col < matrix[line].length; col++)
                {
                    if (col == 1)
                        matrix[line][col] = '+';
                    else
                        matrix[line][col] = '-';
                }
            }
            // empty line
            else if (line % 2 != 0)
            {
                for (int col = 0; col < matrix[line].length; col++)
                {
                    if (col == 1)
                        matrix[line][col] = '|';
                    else
                        matrix[line][col] = ' ';
                }
            }
            // border-line - 0 values, ^ indicates the start of the word
            else if (line == 2)
            {
                for (int col = 0; col < matrix[line].length; col++)
                {
                    if (col == 0)
                        matrix[line][col] = '^';
                    else if (col == 1)
                        matrix[line][col] = '|';
                    else if (col % 2 == 0)
                        matrix[line][col] = ' ';
                    else if (col > 2)
                        matrix[line][col] = '0';
                }
            }
            // first column is the letter of the second word followed by
            // space, delimiter, a further space and the direction value
            else
            {
                for (int col = 0; col < matrix[line].length; col++)
                {
                    if (col == 0)
                    {
                        char c = y.charAt(line/2-2);
                        matrix[line][col] = c;
                    }
                    else if (col == 1)
                        matrix[line][col] = '|';
                    else if (col == 3)
                        matrix[line][col] = '0';
                    else if (col % 2 == 0)
                        matrix[line][col] = ' ';
                    else
                    {
                        int val = type[col/2-2+1][line/2-2+1].getValue();
                        matrix[line][col] = (char)('0'+val);
                    }
                }
            }
        }

        return matrix;
    }

    /**
     * <p>
     * Prints the content of the matrix containing the length values. The output
     * will contain a heightmap like structure containing isoquants indicating
     * the area where all subsequences have the same length.
     * </p>
     */
    private static void printHeightField()
    {
        System.out.println("Height-Field:");
        System.out.println(printMatrix(createLengthMatrix()));
    }

    /**
     * <p>
     * Creates an output matrix for the specified words containing length values
     * for each character couple. The specific value of each character couple
     * marks the length of a subsequence which is reachable from this position.
     * </p>
     * 
     * @return 
     */
    private static char[][] createLengthMatrix()
    {
        char[][] matrix = new char[2+type.length*2-1][];
        for (int i=0; i<matrix.length; i++)
            matrix[i] = new char[2+type.length*2];

        // build the output matrix
        for (int line=0; line<matrix.length; line++)
        {
            // The header column
            if (line == 0)
            {
                for (int col = 0; col < matrix[line].length; col++)
                {
                    if (col == 3)
                        matrix[line][col] = '^';
                    else if (col == 1)
                        matrix[line][col] = '|';
                    // empty column
                    else if (col % 2 == 0)
                        matrix[line][col] = ' ';
                    else if (col > 4)
                    {
                        matrix[line][col] = x.charAt(col / 2 - 2);
                    }
                } 
            }
            else if (line == 1)
            {
                for (int col = 0; col < matrix[line].length; col++)
                {
                    if (col == 1)
                        matrix[line][col] = '+';
                    else
                        matrix[line][col] = '-';
                }
            }
            // empty line
            else if (line % 2 != 0)
            {
                for (int col = 0; col < matrix[line].length; col++)
                {
                    if (col == 1)
                        matrix[line][col] = '|';
                    else
                    {   
                        matrix[line][col] = ' ';
                    }
                }
            }
            // border-line - 0 values, ^ indicates the start of the word
            else if (line == 2)
            {
                for (int col = 0; col < matrix[line].length; col++)
                {
                    if (col == 0)
                        matrix[line][col] = '^';
                    else if (col == 1)
                        matrix[line][col] = '|';
                    else if (col % 2 == 0)
                        matrix[line][col] = ' ';
                    else if (col > 2)
                        matrix[line][col] = '0';
                }
            }
            // first column is the letter of the second word followed by
            // space, delimiter, a further space and the direction value
            else
            {
                for (int col = 0; col < matrix[line].length; col++)
                {
                    if (col == 0)
                    {
                        char c = y.charAt(line/2-2);
                        matrix[line][col] = c;
                    }
                    else if (col == 1)
                        matrix[line][col] = '|';
                    else if (col == 3)
                        matrix[line][col] = '0';
                    else if (col % 2 == 0)
                    {
                        // check if the char to the left and to the top are 
                        // delimiters, if so close it
                        if (matrix[line-2][col] == '|' 
                            && matrix[line-1][col-1] == '-')
                            matrix[line-1][col] = '+';
                        else
                            matrix[line][col] = ' ';
                    }
                    else
                    {
                        int x = col/2-2+1;
                        int y = line/2-2+1;

                        int val = len[x][y];
                        // check if the value to the left is lower than the 
                        // actual value -  insert a separator if so
                        if (x > 0)
                        {
                            if (len[x-1][y] < val)
                            {
                                // as we only write the length values every 
                                // second line we need to fill the previous line
                                // too, else we have a gap in between
                                matrix[line-1][col-1] = '|';
                                matrix[line][col-1] = '|';
                            }
                        }
                        // check if the value to the top is lower than the
                        // actual value - insert a separator if so
                        if (y > 0)
                        {
                            if (len[x][y-1] < val)
                            {
                                // as we only write the length values every
                                // second column we need to fill the previous
                                // column too, else we have a gap in between
                                matrix[line-1][col] = '-';
                                matrix[line-1][col-1] = '-';
                            }
                        }
                        // connect left and top separators
                        if (matrix[line-1][col] == '-' 
                            && matrix[line][col-1] == '|')
                            matrix[line-1][col-1] = '+';

                        matrix[line][col] = (char)('0'+val);
                    }
                }
            }
        }

        return matrix;
    }

    /**
     * <p>
     * Returns the content of the direction matrix as a single {@link String}.
     * </p>
     * 
     * @param matrix The matrix to convert to String
     * @return The String containing the direction values for the longest common
     *         subsequences
     */
    private static String printMatrix(char[][] matrix)
    {
        StringBuilder sb = new StringBuilder();
        for (int line = 0; line < matrix.length; line++)
        {
            for (int col = 0; col < matrix[line].length; col++)
            {
                sb.append(matrix[line][col]);
            }
            sb.append("\n");
        }
        return sb.toString();
    }

    /**
    * Set the DP matrix
    * 
    * <p>
    * Fills two matrices and a list of nodes that achieved the maximum length 
    * for subsequences. The first matrix, <code>len</code> contains the maximum
    * length a subsequence can achieve for each position. The second matrix, 
    * <code>type</code>, contains a direction pointer for backtracking.
    * </p>
    * <p>
    * The filed list of nodes will contain the end nodes which achieved the 
    * greatest length value for a subsequence.
    * </p>
    * 
    * @param s1 The first string
    * @param s2 The second string
    **/
    private static void dpMatrix(String s1, String s2) 
    {
        for (int i = 1; i <= s1.length(); i++) 
        {         
            for (int j = 1; j <= s2.length(); j++) 
            {
                // check if the characters match
                if (s1.charAt(i-1) == s2.charAt(j-1)) 
                {                 
                    len[i][j] = len[i-1][j-1] + 1;                  
                    type[i][j] = Direction.EQUALS;
                }
                else
                {
                    // no match
                    // check if the value to the left is larger then the 
                    // value to the top
                    if(len[i-1][j] > len[i][j-1])
                    {                          
                        len[i][j] = len[i-1][j];
                        type[i][j] = Direction.LEFT;                         
                    }
                    // is value to the top larger than the left one?
                    else if (len[i-1][j] < len[i][j-1])
                    {                          
                        len[i][j] = len[i][j-1];
                        type[i][j] = Direction.TOP;                     
                    }                   
                    else
                    {
                        // both values, the left one and the top one are 
                        // identical so it does not matter which value we are
                        // taking later on
                        len[i][j] = len[i][j-1];
                        type[i][j] = Direction.SPLIT;                     
                    }
                }
                // save the end-nodes that achieve the longest commong 
                // subsequence
                if(len[i][j] > maxLength)
                {
                    maxNodelist.clear();
                    maxLength = len[i][j];
                    maxNodelist.add(i + "," + j);
                }
                else if(len[i][j] == maxLength)
                {
                    maxNodelist.add(i + "," + j);
                }   
            }// End of for
        }// End of for
    }   

    /**
     * <p>
     * Backtrack from (i, j). Find out LCS and record the location of the
     * strings respectively
     * </p>
     * 
     * @param s1 1st string
     * @param s2 2nd string
     * @param i row index in the matrix
     * @param j column index in the matrix
     * @return List<List<String>>, outer List collect three inner List in order: 
     *         LCS string, 1st string LCS location, 2nd string LCS location
     */
    private static List<List<String>> backTrack(String s1, String s2, int i, int j)
    {
       if (i == 0 || j == 0) 
       {
            List<List<String>> list = new ArrayList<>();
            List<String> lcsList = new ArrayList<>();
            List<String> xList = new ArrayList<>();
            List<String> yList = new ArrayList<>();

            lcsList.add("");
            xList.add("");
            yList.add("");

            list.add(lcsList);
            list.add(xList);
            list.add(yList);

            return list;
        }

        if(Direction.EQUALS.equals(type[i][j]))
        {
            List<List<String>> resultList = new ArrayList<>();
            List<String> resultLcsList = new ArrayList<>();
            List<String> resultXList = new ArrayList<>();
            List<String> resultYList = new ArrayList<>();

            List<List<String>> list = backTrack(s1, s2, i - 1, j - 1);

            List<String> lcsList = list.get(0);
            List<String> xList = list.get(1);
            List<String> yList = list.get(2);

            for(String s: lcsList)
            {
                resultLcsList.add(s + s1.charAt(i - 1));                    
            }
            for(String s: xList)
            {
                resultXList.add(s + " " + i);
            }
            for(String s: yList)
            {
                resultYList.add(s + " " + j);
            }

            resultList.add(resultLcsList);
            resultList.add(resultXList);
            resultList.add(resultYList);

            return resultList;

        }
        else if(Direction.LEFT.equals(type[i][j]))
        {
            List<List<String>> list = backTrack(s1, s2, i-1, j);
            return list;
        }
        else if(Direction.TOP.equals(type[i][j]))
        {
            List<List<String>> list = backTrack(s1, s2, i, j-1);
            return list;
        }
        else
        {
            // backtrack to the left
            List<List<String>> leftMove = backTrack(s1, s2, i-1, j);
            // backtrack to the top
            List<List<String>> topMove = backTrack(s1, s2, i, j-1);

            List<String> lcsList = leftMove.get(0);
            List<String> xList = leftMove.get(1);
            List<String> yList = leftMove.get(2);

            lcsList.addAll(topMove.get(0));
            xList.addAll(topMove.get(1));
            yList.addAll(topMove.get(2));

            return leftMove;
        }
    }
}

And the added enumeration to give the directions a bit more semantics:

package lcs;

/**
 * <p>
 * Enumeration of the possible direction for backtracking.
 * </p>
 */
public enum Direction
{
    /** will result in a single move to the top as well as to the left **/
    EQUALS(1),
    /** will result in a move to the left **/
    LEFT(2),
    /** will result in a move to the top **/
    TOP(3),
    /** will result in splitting the move to follow both directions at once: 
     * to the left and to the top **/
    SPLIT(4);

    /** will hold an int value representing the defined direction **/
    private final int value;

    /**
     * <p>
     * Initializes the enumeration value with an int-value.
     * </p>
     * 
     * @param value The int value to assign to the enumeration value
     */
    private Direction(int value)
    {
        this.value = value;
    }

    /**
     * <p>
     * Returns the int representation of the corresponding enumeration.
     * </p>
     * 
     * @return The int value of this enumeration value
     */
    public int getValue()
    {
        return this.value;
    }  
}

Executing this application will result in the following output:

Height-Field:
 | ^ A A C A D B C D A D C B
-+--------------------------
^| 0 0 0 0 0 0 0 0 0 0 0 0 0
 |          +---------------
D| 0 0 0 0 0|1 1 1 1 1 1 1 1
 |      +---+   +-----------
C| 0 0 0|1 1 1 1|2 2 2 2 2 2
 |  +---+ +-----+   +-------
A| 0|1 1 1|2 2 2 2 2|3 3 3 3
 |  |   +-+     +---+   +---
C| 0|1 1|2 2 2 2|3 3 3 3|4 4
 |  |   |   +---+ +-----+   
D| 0|1 1|2 2|3 3 3|4 4 4 4 4
 |  |   |   |   +-+     +---
C| 0|1 1|2 2|3 3|4 4 4 4|5 5
 |  |   |   | +-+       | +-
B| 0|1 1|2 2|3|4 4 4 4 4|5|6
 |  |   |   | |         | | 
B| 0|1 1|2 2|3|4 4 4 4 4|5|6
 |  |   |   | |   +-----+ | 
D| 0|1 1|2 2|3|4 4|5 5 5 5|6
 |  |   |   | |   |       | 
B| 0|1 1|2 2|3|4 4|5 5 5 5|6
 |  | +-+ +-+ |   | +-----+ 
A| 0|1|2 2|3 4|4 4|5|6 6 6 6
 |  | |   | +-+   | | +-----
D| 0|1|2 2|3|4 4 4|5|6|7 7 7

Snakes:
 | ^ A A C A D B C D A D C B
-+--------------------------
^| 0 0 0 0 0 0 0 0 0 0 0 0 0
 |   | |                    
D| 0-4-4 4 4 1 2 2 1 2 1 2 2
 |   |  \                   
C| 0-4 4 1 2 4 4 1 2 2 2 1 2
 |    \   \                 
A| 0 1 1 4 1 2 2 4 4 1 2 2 2
 |      \  |                
C| 0 3 4 1-4 4 4 1 2 4 4 1 2
 |          \               
D| 0 3 4 3 4 1-2 4 1 2 1 4 4
 |           |  \           
C| 0 3 4 1 4 3 4 1 4 4 4 1 2
 |           |\  |          
B| 0 3 4 3 4 3 1-4 4 4 4 3 1
 |            \  |          
B| 0 3 4 3 4 3 1-4 4 4 4 3 1
 |                \         
D| 0 3 4 3 4 1 3 4 1 2 1 4 3
 |                 |        
B| 0 3 4 3 4 3 1 4 3 4 4 4 1
 |                  \       
A| 0 1 1 4 1 4 3 4 3 1 2 2 4
 |                    \     
D| 0 3 3 4 3 1 4 4 1 3 1-2-2

--- Output ---
Max. length = 7
LCS: ACDBDAD, in X:  2 3 5 6 8 9 10, in Y:  3 4 5 7 9 11 12
LCS: ACDBDAD, in X:  2 3 5 6 8 9 10, in Y:  3 4 5 8 9 11 12
LCS: ACDCDAD, in X:  2 3 5 7 8 9 10, in Y:  3 4 5 6 9 11 12
LCS: CADBDAD, in X:  3 4 5 6 8 9 10, in Y:  2 3 5 7 9 11 12
LCS: CADBDAD, in X:  3 4 5 6 8 9 10, in Y:  2 3 5 8 9 11 12
LCS: CADCDAD, in X:  3 4 5 7 8 9 10, in Y:  2 3 5 6 9 11 12

So to me 6 solutions seem pretty plausible. As already mentioned in my comment, please post your 2 missing solutions so we may evaluate if either they are wrong or why they don't appear within the results of your dpMatrix() method.

Roman Vottner
  • 12,213
  • 5
  • 46
  • 63
  • Another missing 3 solutions are: ACDBDAD , in X: 1 3 5 6 8 9 10 , in Y: 3 4 5 7 9 11 12 ACDCDAD , in X: 1 3 5 7 8 9 10 , in Y: 3 4 5 6 9 11 12 ACDBDAD , in X: 1 3 5 6 8 9 10 , in Y: 3 4 5 8 9 11 12 Thanks for your comment, Roman.
    – Wei-Yen Bruce Lin Nov 28 '13 at 18:50