3

We can find the LCS(Longest Common Subsequence) of two strings with DP(Dynamic Programming). By keeping track with DP Table we can get the LCS. But if there exists more than one LCS how can we get all of them?

Example:

string1 : bcab
string2 : abc

Here both "ab" and "bc" are LCS.

Mostafiz Rahman
  • 6,939
  • 6
  • 45
  • 68

3 Answers3

2

Here is a working java solution. For explanation you can see my answer How to print all possible solutions for Longest Common subsequence

static int arr[][];
static void lcs(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))
                arr[i][j] = arr[i - 1][j - 1] + 1;
            else
                arr[i][j] = Math.max(arr[i - 1][j], arr[i][j - 1]);
        }
    }
}

static Set<String> lcs(String s1, String s2, int len1, int len2) {
    if (len1 == 0 || len2 == 0) {
        Set<String> set = new HashSet<String>();
        set.add("");
        return set;
    }
    if (s1.charAt(len1 - 1) == s2.charAt(len2 - 1)) {
        Set<String> set = lcs(s1, s2, len1 - 1, len2 - 1);
        Set<String> set1 = new HashSet<>();
        for (String temp : set) {
            temp = temp + s1.charAt(len1 - 1);
            set1.add(temp);
        }
        return set1;
    } else {
        Set<String> set = new HashSet<>();
        Set<String> set1 = new HashSet<>();
        if (arr[len1 - 1][len2] >= arr[len1][len2 - 1]) {
            set = lcs(s1, s2, len1 - 1, len2);
        }
        if (arr[len1][len2 - 1] >= arr[len1 - 1][len2]) {
            set1 = lcs(s1, s2, len1, len2 - 1);
        }
        for (String temp : set) {
            set1.add(temp);
        }
        //System.out.println("In lcs" + set1);
        return set1;

    }
}


public static void main(String[] args) {
    String s1 = "bcab";
    String s2 = "abc";
    arr = new int[s1.length() + 1][s2.length() + 1];
    lcs(s1, s2);
    System.out.println(lcs(s1, s2, s1.length(), s2.length()));
}
Community
  • 1
  • 1
Kundan
  • 51
  • 6
  • String s1 = "aaaaaaaaaaaaaaaaaaaaaaaaaa"; String s2 = "bbbbbbbbbbbbbbbbbbbbbbbbbb"; makes it exponential. I assume OP wants a polynomial solution. – Ishamael Oct 26 '16 at 04:34
1

When you calculate a cell in the DP table, keep a backpointer to the previous cell used for that result. If there is a tie, keep multiple backpointers for all of the tied results. Then retrace the path using the backpointers, following all paths.

yzernik
  • 1,050
  • 2
  • 12
  • 18
  • 1
    Actually, I can even do this without keeping an extra backpointer. I can use the precalculated DP table to do so. But the problem(to me) occurs when there is a tie. I've written an iterative approach. So I'm confused how to follow both of the paths of the tie. Can anyone help me to solve this case? – Mostafiz Rahman May 31 '13 at 02:13
  • 1
    You could have a recursive function to findPaths from a certain coordinate in the DP table, returning a set of paths. This could be called initially from the last cell in the table. – yzernik May 31 '13 at 02:26
1

Here is a commented Java program to find all possible lcs.

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class LongestCommonSubsequence {

    public static int[][] LCSmatrix(String X, String Y) {
        //we ignore the top most row and left most column in this matrix
        //so we add 1 and create a matrix with appropriate row and column size 
        int m = X.length() + 1, n = Y.length() + 1;

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

        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                //since we added 1 to row size and column size,
                // we substract 1 from i,j to find the char at that index
                if (X.charAt(i - 1) == Y.charAt(j - 1)) {
                    c[i][j] = c[i - 1][j - 1] + 1;
                } else if (c[i - 1][j] >= c[i][j - 1]) {
                    c[i][j] = c[i - 1][j];
                } else {
                    c[i][j] = c[i][j - 1];
                }
            }
        }
        printMatrix(c);
        return c;
    }

    public static void printMatrix(int[][] grid) {
        for (int r = 0; r < grid.length; r++) {
            for (int c = 0; c < grid[r].length; c++) {
                System.out.print(grid[r][c] + " ");
            }
            System.out.println();
        }
    }

    public static void allLCS(int[][] c, String X, String Y, int i, int j, Set<String> setLCS, String s) {
        //return when either of the string length is 0
        if (i == 0 || j == 0) {
            setLCS.add(s);
            return;
        }

        //if last characters are equal, they belong in lcs
        if (X.charAt(i - 1) == Y.charAt(j - 1)) {
            //prepend the char to lcs since, we are going backwards
            s = X.charAt(i - 1) + s;
            //continue finding lcs in substrings X.substring(0,i-1) and Y.substring(0,j-1)
            allLCS(c, X, Y, i - 1, j - 1, setLCS, s);
        } // if there is a tie in matrix cells, we backtrack in both ways,
        // else one way, which ever is greater
        else if (c[i - 1][j] == c[i][j - 1]) {
            //continue finding lcs in substring X.substring(0,i-1)
            allLCS(c, X, Y, i - 1, j, setLCS, s);
            //continue finding lcs in substring Y.substring(0,j-1)
            allLCS(c, X, Y, i, j - 1, setLCS, s);
        } else if (c[i - 1][j] > c[i][j - 1]) {
            allLCS(c, X, Y, i - 1, j, setLCS, s);
        } else {
            allLCS(c, X, Y, i, j - 1, setLCS, s);
        }

    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.println(" Enter String X and Y : ");

        String X = sc.next();
        String Y = sc.next();

        sc.close();

        Set<String> set = new HashSet<String>();
        allLCS(LCSmatrix(X, Y), X, Y, X.length(), Y.length(), set, "");

        System.out.println(set.toString());
    }

}
Charan
  • 971
  • 2
  • 11
  • 27