📜  按字典顺序打印所有最长的公共子序列

📅  最后修改于: 2021-04-24 21:57:40             🧑  作者: Mango

给您两个字符串。现在您必须按字典顺序打印所有最长的公共子序列吗?
例子:

Input : str1 = "abcabcaa", str2 = "acbacba"
Output: ababa
        abaca
        abcba
        acaba
        acaca
        acbaa
        acbca

此问题是最长公共子序列的扩展。我们首先找到LCS的长度,然后使用备忘(或动态编程)将所有LCS存储在2D表中。然后,我们在两个字符串搜索从’a’到’z’的所有字符(以输出排序顺序)。如果在字符串中都找到一个字符,并且当前字符位置导致了LCS,则我们递归搜索所有当前LCS长度加1的事件。
下面是算法的实现。

C++
// C++ program to find all LCS of two strings in
// sorted order.
#include
#define MAX 100
using namespace std;
 
// length of lcs
int lcslen = 0;
 
// dp matrix to store result of sub calls for lcs
int dp[MAX][MAX];
 
// A memoization based function that returns LCS of
// str1[i..len1-1] and str2[j..len2-1]
int lcs(string str1, string str2, int len1, int len2,
                                      int i, int j)
{
    int &ret = dp[i][j];
 
    // base condition
    if (i==len1 || j==len2)
        return ret = 0;
 
    // if lcs has been computed
    if (ret != -1)
        return ret;
 
    ret = 0;
 
    // if characters are same return previous + 1 else
    // max of two sequences after removing i'th and j'th
    // char one by one
    if (str1[i] == str2[j])
        ret = 1 + lcs(str1, str2, len1, len2, i+1, j+1);
    else
        ret = max(lcs(str1, str2, len1, len2, i+1, j),
                  lcs(str1, str2, len1, len2, i, j+1));
    return ret;
}
 
// Function to print all routes common sub-sequences of
// length lcslen
void printAll(string str1, string str2, int len1, int len2,
              char data[], int indx1, int indx2, int currlcs)
{
    // if currlcs is equal to lcslen then print it
    if (currlcs == lcslen)
    {
        data[currlcs] = '\0';
        puts(data);
        return;
    }
 
    // if we are done with all the characters of both string
    if (indx1==len1 || indx2==len2)
        return;
 
    // here we have to print all sub-sequences lexicographically,
    // that's why we start from 'a'to'z' if this character is
    // present in both of them then append it in data[] and same
    // remaining part
    for (char ch='a'; ch<='z'; ch++)
    {
        // done is a flag to tell that we have printed all the
        // subsequences corresponding to current character
        bool done = false;
 
        for (int i=indx1; i


Java
// Java program to find all LCS of two strings in
// sorted order.
class GFG
{
  static int MAX = 100;
 
  // length of lcs
  static int lcslen = 0;
 
  // dp matrix to store result of sub calls for lcs
  static int[][] dp = new int[MAX][MAX];
 
  // A memoization based function that returns LCS of
  // str1[i..len1-1] and str2[j..len2-1]
  static int lcs(String str1, String str2,
                 int len1, int len2, int i, int j)
  {
    int ret = dp[i][j];
 
    // base condition
    if (i == len1 || j == len2)
      return ret = 0;
 
    // if lcs has been computed
    if (ret != -1)
      return ret;      
    ret = 0;
 
    // if characters are same return previous + 1 else
    // max of two sequences after removing i'th and j'th
    // char one by one
    if (str1.charAt(i) == str2.charAt(j))
      ret = 1 + lcs(str1, str2, len1, len2, i + 1, j + 1);
    else
      ret = Math.max(lcs(str1, str2, len1, len2, i + 1, j),
                     lcs(str1, str2, len1, len2, i, j + 1));
    return ret;
  }
 
  // Function to print all routes common sub-sequences of
  // length lcslen
  static void printAll(String str1, String str2, int len1, int len2,
                       char[] data, int indx1, int indx2, int currlcs)
  {
 
    // if currlcs is equal to lcslen then print it
    if (currlcs == lcslen)
    {
      data[currlcs] = '\0';
      System.out.println(new String(data));
      return;
    }
 
    // if we are done with all the characters of both string
    if (indx1 == len1 || indx2 == len2)
      return;
 
    // here we have to print all sub-sequences lexicographically,
    // that's why we start from 'a'to'z' if this character is
    // present in both of them then append it in data[] and same
    // remaining part
    for (char ch ='a'; ch <='z'; ch++)
    {
 
      // done is a flag to tell that we have printed all the
      // subsequences corresponding to current character
      boolean done = false;
 
      for (int i = indx1; i < len1; i++)
      {
 
        // if character ch is present in str1 then check if
        // it is present in str2
        if (ch == str1.charAt(i))
        {
          for (int j = indx2; j < len2; j++)
          {
 
            // if ch is present in both of them and
            // remaining length is equal to remaining
            // lcs length then add ch in sub-sequenece
            if (ch == str2.charAt(j) &&
                lcs(str1, str2, len1, len2, i, j) == lcslen - currlcs)
            {
              data[currlcs] = ch;
              printAll(str1, str2, len1, len2,
                       data, i + 1, j + 1, currlcs + 1);
              done = true;
              break;
            }
          }
        }
 
        // If we found LCS beginning with current character. 
        if (done)
          break;
      }
    }
  }
 
  // This function prints all LCS of str1 and str2
  // in lexicographic order.
  static void prinlAllLCSSorted(String str1, String str2)
  {
 
    // Find lengths of both strings
    int len1 = str1.length(), len2 = str2.length();
 
    // Find length of LCS
    for(int i = 0; i < MAX; i++)
    {
      for(int j = 0; j < MAX; j++)
      {
        dp[i][j] = -1;
      }
    }
    lcslen = lcs(str1, str2, len1, len2, 0, 0);
 
    // Print all LCS using recursive backtracking
    // data[] is used to store individual LCS.
    char[] data = new char[MAX];
    printAll(str1, str2, len1, len2, data, 0, 0, 0);
  }
 
  // Driver code
  public static void main(String[] args)
  {
    String str1 = "abcabcaa", str2 = "acbacba";
    prinlAllLCSSorted(str1, str2);
  }
}
 
// This code is contributed by divyesh072019


Python3
# Python3 program to find all LCS of two strings in
# sorted order.
MAX=100
lcslen = 0
 
# dp matrix to store result of sub calls for lcs
dp=[[-1 for i in range(MAX)] for i in range(MAX)]
 
# A memoization based function that returns LCS of
# str1[i..len1-1] and str2[j..len2-1]
def lcs(str1, str2, len1, len2, i, j):
 
    # base condition
    if (i == len1 or j == len2):
        dp[i][j] = 0
        return dp[i][j]
 
    # if lcs has been computed
    if (dp[i][j] != -1):
        return dp[i][j]
 
    ret = 0
 
    # if characters are same return previous + 1 else
    # max of two sequences after removing i'th and j'th
    # char one by one
    if (str1[i] == str2[j]):
        ret = 1 + lcs(str1, str2, len1, len2, i + 1, j + 1)
    else:
        ret = max(lcs(str1, str2, len1, len2, i + 1, j),
                  lcs(str1, str2, len1, len2, i, j + 1))
    dp[i][j] = ret
    return ret
 
# Function to prall routes common sub-sequences of
# length lcslen
def printAll(str1, str2, len1, len2,data, indx1, indx2, currlcs):
     
    # if currlcs is equal to lcslen then prit
    if (currlcs == lcslen):
        print("".join(data[:currlcs]))
        return
 
    # if we are done with all the characters of both string
    if (indx1 == len1 or indx2 == len2):
        return
 
    # here we have to prall sub-sequences lexicographically,
    # that's why we start from 'a'to'z' if this character is
    # present in both of them then append it in data[] and same
    # remaining part
    for ch in range(ord('a'),ord('z') + 1):
 
        # done is a flag to tell that we have printed all the
        # subsequences corresponding to current character
        done = False
 
        for i in range(indx1,len1):
            # if character ch is present in str1 then check if
            # it is present in str2
            if (chr(ch)==str1[i]):
              for j in range(indx2, len2):
 
                # if ch is present in both of them and
                # remaining length is equal to remaining
                # lcs length then add ch in sub-sequenece
                if (chr(ch) == str2[j] and lcs(str1, str2, len1, len2, i, j) == lcslen-currlcs):
                  data[currlcs] = chr(ch)
                  printAll(str1, str2, len1, len2, data, i + 1, j + 1, currlcs + 1)
                  done = True
                  break
 
            # If we found LCS beginning with current character.
            if (done):
                break
 
# This function prints all LCS of str1 and str2
# in lexicographic order.
def prinlAllLCSSorted(str1, str2):
    global lcslen
    # Find lengths of both strings
    len1,len2 = len(str1),len(str2)
 
    lcslen = lcs(str1, str2, len1, len2, 0, 0)
 
    # Prall LCS using recursive backtracking
    # data[] is used to store individual LCS.
    data = ['a' for i in range(MAX)]
    printAll(str1, str2, len1, len2, data, 0, 0, 0)
 
# Driver program to run the case
if __name__ == '__main__':
    str1 = "abcabcaa"
    str2 = "acbacba"
    prinlAllLCSSorted(str1, str2)
 
# This code is contributed by mohit kumar 29


C#
// C# program to find all LCS of two strings in
// sorted order.
using System;
class GFG
{   
    static int MAX = 100;
     
    // length of lcs
    static int lcslen = 0;
       
    // dp matrix to store result of sub calls for lcs
    static int[,] dp = new int[MAX,MAX];
       
    // A memoization based function that returns LCS of
    // str1[i..len1-1] and str2[j..len2-1]
    static int lcs(string str1, string str2,
                   int len1, int len2, int i, int j)
    {
        int ret = dp[i, j];
       
        // base condition
        if (i == len1 || j == len2)
            return ret = 0;
       
        // if lcs has been computed
        if (ret != -1)
            return ret;
       
        ret = 0;
       
        // if characters are same return previous + 1 else
        // max of two sequences after removing i'th and j'th
        // char one by one
        if (str1[i] == str2[j])
            ret = 1 + lcs(str1, str2, len1, len2, i + 1, j + 1);
        else
            ret = Math.Max(lcs(str1, str2, len1, len2, i + 1, j),
                      lcs(str1, str2, len1, len2, i, j + 1));
        return ret;
    }
       
    // Function to print all routes common sub-sequences of
    // length lcslen
    static void printAll(string str1, string str2, int len1, int len2,
                  char[] data, int indx1, int indx2, int currlcs)
    {
        // if currlcs is equal to lcslen then print it
        if (currlcs == lcslen)
        {
            data[currlcs] = '\0';
            Console.WriteLine(new string(data));
            return;
        }
       
        // if we are done with all the characters of both string
        if (indx1 == len1 || indx2 == len2)
            return;
       
        // here we have to print all sub-sequences lexicographically,
        // that's why we start from 'a'to'z' if this character is
        // present in both of them then append it in data[] and same
        // remaining part
        for (char ch='a'; ch<='z'; ch++)
        {
            // done is a flag to tell that we have printed all the
            // subsequences corresponding to current character
            bool done = false;
       
            for (int i = indx1; i < len1; i++)
            {
                // if character ch is present in str1 then check if
                // it is present in str2
                if (ch == str1[i])
                {
                  for (int j = indx2; j < len2; j++)
                  {
                    // if ch is present in both of them and
                    // remaining length is equal to remaining
                    // lcs length then add ch in sub-sequenece
                    if (ch == str2[j] &&
                      lcs(str1, str2, len1, len2, i, j) == lcslen-currlcs)
                    {
                      data[currlcs] = ch;
                      printAll(str1, str2, len1, len2, data, i+1, j+1, currlcs+1);
                      done = true;
                      break;
                    }
                  }
                }
       
                // If we found LCS beginning with current character. 
                if (done)
                    break;
            }
        }
    }
       
    // This function prints all LCS of str1 and str2
    // in lexicographic order.
    static void prinlAllLCSSorted(string str1, string str2)
    {
        // Find lengths of both strings
        int len1 = str1.Length, len2 = str2.Length;
       
        // Find length of LCS
        for(int i = 0; i < MAX; i++)
        {
            for(int j = 0; j < MAX; j++)
            {
                dp[i, j] = -1;
            }
        }
        lcslen = lcs(str1, str2, len1, len2, 0, 0);
       
        // Print all LCS using recursive backtracking
        // data[] is used to store individual LCS.
        char[] data = new char[MAX];
        printAll(str1, str2, len1, len2, data, 0, 0, 0);
    }
 
  // Driver code
  static void Main()
  {
    string str1 = "abcabcaa", str2 = "acbacba";
    prinlAllLCSSorted(str1, str2);
  }
}
 
// This code is contributed by divyeshrabadiya07


输出:

ababa
abaca
abcba
acaba
acaca
acbaa
acbca