【问题标题】:How to print all possible solutions for Longest Common subsequence如何打印最长公共子序列的所有可能解决方案
【发布时间】:2014-03-10 11:52:54
【问题描述】:

我想打印 LCS 问题的所有可能解决方案。

两个字符串 abcbdab 和 bdcaba 应该打印以下 3 个字符串: bdab,bcba,bcab。

C是根据算法取值的全局矩阵表,m,n是序列a,b的长度。

但是输出有些出乎意料。

#include<stdio.h>
#include<conio.h>
int co=0,m=0,n=0,c[10][10];
char a[10],b[10];
void main()
{
    int i,j;
    clrscr();
    printf("Enter Two strings: ");
    scanf("%s",a);
    scanf("%s",b);
    m=strlen(a);
    n=strlen(b);
    for(i=0;i<=m;i++)
    {
        for(j=0;j<=n;j++)
        {   if(i==0 || j==0)
            {
                c[i][j]=0;
            }
            else if(a[i-1]==b[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];
            }
        }
    }
    for(i=0;i<=m;i++)
    {
        for(j=0;j<=n;j++)
        {
            printf("%d\t",c[i][j]);
        }
        printf("\n");
    }
    print(m,n);
    getch();
}
print(int i,int j)
{
    if(i==0 || j==0)
        return 0;
    else if(a[i-1]==b[j-1])
    {
        print(i-1,j-1);
        if(co==c[m][n])
        {
            co=0;
            printf("\n");
        }
        printf("%c",a[i-1]);
        co++;
    }
    else if(c[i-1][j]==c[i][j-1])
    {
        print(i-1,j);
        print(i,j-1);
    }
    else if(c[i][j-1]>=c[i-1][j])
        print(i,j-1);
    else
        print(i-1,j);
    return;
}

【问题讨论】:

    标签: lcs longest-substring


    【解决方案1】:

    您可以在此处找到如何执行此操作的递归方法:Reading out all LCSs

    这是我在 Java 中使用这种方法的代码:

    private Set<String> lcs(int[][] dp, String fst, String snd, int i, int j) {
        Set<String> lcss = new HashSet<>();
    
        if (i == 0 || j == 0) {
            lcss.add("");
        } else if (fst.charAt(i - 1) == snd.charAt(j - 1)) {
            for (String lcs : lcs(dp, fst, snd, i - 1, j - 1)) {
                lcss.add(lcs + fst.charAt(i - 1));
            }
        } else {
            if (dp[i - 1][j] >= dp[i][j - 1]) {
                lcss.addAll(lcs(dp, fst, snd, i - 1, j));
            }
    
            if (dp[i][j - 1] >= dp[i - 1][j]) {
                lcss.addAll(lcs(dp, fst, snd, i, j - 1));
            }
        }
        return lcss;
    }
    

    【讨论】:

    • 列出了查找所有LCS过程中产生的所有字符串。
    • 忽略我的第一句话,上面的算法是正确的!!
    • @rdiachenko : 打印出所有 LCS o(nm) 的时间复杂度是多少,其中 n 是第一个字符串的长度,m 是第二个字符串的长度?
    • @user1477232,不,在最坏的情况下,时间复杂度约为 (n + m) * 2^(max(n, m)),其中 (n + m) 是递归树和 2^(max(n, m)) 是递归树中每一层的递归调用的近似数量。当输入字符串由完全不同的字符(例如:“abc”和“xyz”)组成时,您可以看到最坏的情况。
    【解决方案2】:

    这里是带有 cmets 的 Java 代码,解释了如何打印所有可能的 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());
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      您的源代码没有打印 lcs。它实际上是在计算lcs的长度。您提供的源代码完全错误。首先尝试打印一个 lcs。然后扩展该解决方案以打印所有 lcs。为了您的帮助,下面给出了有效的 java 解决方案。

      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 = "abcbdab";
          String s2 = "bdcaba ";
          arr = new int[s1.length() + 1][s2.length() + 1];
          lcs(s1, s2);
          System.out.println(lcs(s1, s2, s1.length(), s2.length()));
      }
      

      如果字符串的最后一个字符相等,那么它们必须在 lcs 中。如果它们不相等,则 lcs 将从矩阵的上侧或矩阵的左侧构造,具体取决于哪个值更大。如果两个值相等,则 lcs 将从两侧构造。因此,请继续构建 lcs,直到您构建完所有 lcs 并将它们存储在一个集合中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-04
        • 1970-01-01
        • 2014-07-23
        • 2014-08-24
        • 2015-06-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多