📜  最长重复子序列

📅  最后修改于: 2021-04-24 20:42:04             🧑  作者: Mango

给定一个字符串,请打印最长的重复子序列,以使两个子序列在相同位置没有相同的字符串字符,即,两个子序列中的任何第i个字符在原始字符串都不应具有相同的索引。

例子:

Input: str = "aabb"
Output: "ab"

Input: str = "aab"
Output: "a"
The two subsequence are 'a'(first) and 'a' 
(second). Note that 'b' cannot be considered 
as part of subsequence as it would be at same
index in both.

这个问题只是最长公共子序列问题的修改。这个想法是要找到LCS(str,str),其中str是输入字符串,但要限制两个字符同时,它们在两个字符串不应位于相同的索引上。
我们已经讨论了找到最长重复子序列长度的解决方案。

C++
// Refer https://www.geeksforgeeks.org/longest-repeating-subsequence/
// for complete code.
// This function mainly returns LCS(str, str)
// with a condition that same characters at
// same index are not considered.
int findLongestRepeatingSubSeq(string str)
{
    int n = str.length();
  
    // Create and initialize DP table
    int dp[n+1][n+1];
  //initlizing first row and column in dp table
    for(int i=0;i<=n;i++){
      dp[i][0] =0;
      dp[0][i] =0;
    }
   
  
    // Fill dp table (similar to LCS loops)
    for (int i=1; i<=n; i++)
    {
        for (int j=1; j<=n; j++)
        {
            // If characters match and indexes are
            // not same
            if (str[i-1] == str[j-1] && i != j)
                dp[i][j] =  1 + dp[i-1][j-1];         
                       
            // If characters do not match
            else
                dp[i][j] = max(dp[i][j-1], dp[i-1][j]);
        }
    }
    return dp[n][n];
}


Java
// Refer https://www.geeksforgeeks.org/longest-repeating-subsequence/
// for complete code.
// This function mainly returns LCS(str, str)
// with a condition that same characters at
// same index are not considered.
static int findLongestRepeatingSubSeq(String str)
{
    int n = str.length();
   
    // Create and initialize DP table
    int dp[][] = new int[n+1][n+1];
    for (int i=0; i<=n; i++)
        for (int j=0; j<=n; j++)
            dp[i][j] = 0;
   
    // Fill dp table (similar to LCS loops)
    for (int i=1; i<=n; i++)
    {
        for (int j=1; j<=n; j++)
        {
            // If characters match and indexes are
            // not same
            if (str.charAt(i-1)== str.charAt(j-1) && i != j)
                dp[i][j] =  1 + dp[i-1][j-1];         
                        
            // If characters do not match
            else
                dp[i][j] = Math.max(dp[i][j-1], dp[i-1][j]);
        }
    }
    return dp[n][n];
}


Python3
# Python method for Longest Repeated
# Subsequence
 
# Refer https://www.geeksforgeeks.org/longest-repeating-subsequence/
# for complete code.
# This function mainly returns LCS(str, str)
# with a condition that same characters at
# same index are not considered.
def findLongestRepeatingSubSeq(str):
    n = len(str)
 
    # Create and initialize DP table
    dp = [[0 for k in range(n+1)] for l in range(n+1)]
 
    # Fill dp table (similar to LCS loops)
    for i in range(1, n+1):
        for j in range(1, n+1):
            # If characters match and indices are not same
            if (str[i-1] == str[j-1] and i != j):
                dp[i][j] = 1 + dp[i-1][j-1]
 
            # If characters do not match
            else:
                dp[i][j] = max(dp[i][j-1], dp[i-1][j])
 
    return dp[n][n]
 
# This code is contributed by Soumen Ghosh


C#
// Refer https://www.geeksforgeeks.org/longest-repeating-subsequence/
// for complete code.
// This function mainly returns LCS(str, str)
// with a condition that same characters at
// same index are not considered.
static int findLongestRepeatingSubSeq(String str)
{
    int n = str.Length;
     
    // Create and initialize DP table
    int [,]dp = new int[n+1,n+1];
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= n; j++)
            dp[i, j] = 0;
     
    // Fill dp table (similar to LCS loops)
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            // If characters match and indexes are
            // not same
            if (str[i-1]== str[j-1] && i != j)
                dp[i, j] = 1 + dp[i-1, j-1];        
                         
            // If characters do not match
            else
                dp[i,j] = Math.Max(dp[i, j-1], dp[i-1, j]);
        }
    }
    return dp[n, n];
}
 
// This code is contributed by 29AjayKumar


PHP


C++
// C++ program to find the longest repeated
// subsequence
#include 
using namespace std;
 
// This function mainly returns LCS(str, str)
// with a condition that same characters at
// same index are not considered.
string longestRepeatedSubSeq(string str)
{
    // THIS PART OF CODE IS SAME AS BELOW POST.
    // IT FILLS dp[][]
    // https://www.geeksforgeeks.org/longest-repeating-subsequence/
    // OR the code mentioned above.
    int n = str.length();
    int dp[n+1][n+1];
    for (int i=0; i<=n; i++)
        for (int j=0; j<=n; j++)
            dp[i][j] = 0;
    for (int i=1; i<=n; i++)
        for (int j=1; j<=n; j++)
            if (str[i-1] == str[j-1] && i != j)
                dp[i][j] =  1 + dp[i-1][j-1];
            else
                dp[i][j] = max(dp[i][j-1], dp[i-1][j]);
 
 
    // THIS PART OF CODE FINDS THE RESULT STRING USING DP[][]
    // Initialize result
    string res = "";
 
    // Traverse dp[][] from bottom right
    int i = n, j = n;
    while (i > 0 && j > 0)
    {
        // If this cell is same as diagonally
        // adjacent cell just above it, then
        // same characters are present at
        // str[i-1] and str[j-1]. Append any
        // of them to result.
        if (dp[i][j] == dp[i-1][j-1] + 1)
        {
           res = res + str[i-1];
           i--;
           j--;
        }
 
        // Otherwise we move to the side
        // that that gave us maximum result
        else if (dp[i][j] == dp[i-1][j])
            i--;
        else
            j--;
    }
 
    // Since we traverse dp[][] from bottom,
    // we get result in reverse order.
    reverse(res.begin(), res.end());
 
    return res;
}
 
// Driver Program
int main()
{
    string str = "AABEBCDD";
    cout << longestRepeatedSubSeq(str);
    return 0;
}


Java
// Java program to find the longest repeated
// subsequence
import java.util.*;
 
class GFG
{
 
// This function mainly returns LCS(str, str)
// with a condition that same characters at
// same index are not considered.
static String longestRepeatedSubSeq(String str)
{
    // THIS PART OF CODE IS SAME AS BELOW POST.
    // IT FILLS dp[][]
    // https://www.geeksforgeeks.org/longest-repeating-subsequence/
    // OR the code mentioned above.
    int n = str.length();
    int[][] dp = new int[n + 1][n + 1];
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= n; j++)
            dp[i][j] = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (str.charAt(i - 1) == str.charAt(j - 1) && i != j)
                dp[i][j] = 1 + dp[i - 1][j - 1];
            else
                dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
 
 
    // THIS PART OF CODE FINDS
    // THE RESULT STRING USING DP[][]
    // Initialize result
    String res = "";
 
    // Traverse dp[][] from bottom right
    int i = n, j = n;
    while (i > 0 && j > 0)
    {
        // If this cell is same as diagonally
        // adjacent cell just above it, then
        // same characters are present at
        // str[i-1] and str[j-1]. Append any
        // of them to result.
        if (dp[i][j] == dp[i - 1][j - 1] + 1)
        {
        res = res + str.charAt(i - 1);
        i--;
        j--;
        }
 
        // Otherwise we move to the side
        // that that gave us maximum result
        else if (dp[i][j] == dp[i - 1][j])
            i--;
        else
            j--;
    }
 
    // Since we traverse dp[][] from bottom,
    // we get result in reverse order.
    String reverse = "";
         
         
    for(int k = res.length() - 1; k >= 0; k--)
        {
            reverse = reverse + res.charAt(k);
        }
 
 
    return reverse;
}
 
// Driver code
public static void main(String args[])
{
    String str = "AABEBCDD";
    System.out.println(longestRepeatedSubSeq(str));
}
}
 
// This code is contributed by
// Surendra_Gangwar


Python3
# Python3 program to find the
# longest repeated subsequence
 
# This function mainly returns LCS(str, str)
# with a condition that same characters
# at same index are not considered.
def longestRepeatedSubSeq(str):
    # This part of code is same as
    # below post it fills dp[][]
    # https://www.geeksforgeeks.org/longest-repeating-subsequence/
    # OR the code mentioned above
    n = len(str)
    dp = [[0 for i in range(n+1)] for j in range(n+1)]
     
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            if (str[i-1] == str[j-1] and i != j):
                dp[i][j] = 1 + dp[i-1][j-1]
            else:
                dp[i][j] = max(dp[i][j-1], dp[i-1][j])
 
    # This part of code finds the result
    # string using dp[][] Initialize result
    res = ''
 
    # Traverse dp[][] from bottom right
    i = n
    j = n
    while (i > 0 and j > 0):
        # If this cell is same as diagonally
        # adjacent cell just above it, then
        # same characters are present at
        # str[i-1] and str[j-1]. Append any
        # of them to result.
        if (dp[i][j] == dp[i-1][j-1] + 1):
            res += str[i-1]
            i -= 1
            j -= 1
 
        # Otherwise we move to the side
        # that gave us maximum result.
        elif (dp[i][j] == dp[i-1][j]):
            i -= 1
        else:
            j -= 1
 
    # Since we traverse dp[][] from bottom,
    # we get result in reverse order.
    res = ''.join(reversed(res))
     
    return res
     
# Driver Program
str = 'AABEBCDD'
print(longestRepeatedSubSeq(str))
 
# This code is contributed by Soumen Ghosh


PHP
 0 && $j > 0)
    {
        // If this cell is same as diagonally
        // adjacent cell just above it, then
        // same characters are present at
        // str[i-1] and str[j-1]. Append any
        // of them to result.
        if ($dp[$i][$j] == $dp[$i - 1][$j - 1] + 1)
        {
            $res = $res.$str[$i - 1];
            $i--;
            $j--;
        }
 
        // Otherwise we move to the side
        // that that gave us maximum result
        else if ($dp[$i][$j] == $dp[$i - 1][$j])
            $i--;
        else
            $j--;
    }
 
    // Since we traverse dp[][] from bottom,
    // we get result in reverse order.
    return strrev($res) ;
}
 
// Driver Code
$str = "AABEBCDD";
echo longestRepeatedSubSeq($str);
 
// This code is contributed by Ryuga
?>


C#
// C# program to find the longest repeated
// subsequence
using System;
using System.Collections.Generic;
     
class GFG
{
 
// This function mainly returns LCS(str, str)
// with a condition that same characters at
// same index are not considered.
static String longestRepeatedSubSeq(String str)
{
    // THIS PART OF CODE IS SAME AS BELOW POST.
    // IT FILLS dp[,]
    // https://www.geeksforgeeks.org/longest-repeating-subsequence/
    // OR the code mentioned above.
    int n = str.Length,i,j;
    int[,] dp = new int[n + 1,n + 1];
    for (i = 0; i <= n; i++)
        for (j = 0; j <= n; j++)
            dp[i, j] = 0;
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            if (str[i - 1] == str[j - 1] && i != j)
                dp[i, j] = 1 + dp[i - 1, j - 1];
            else
                dp[i, j] = Math.Max(dp[i, j - 1], dp[i - 1, j]);
 
 
    // THIS PART OF CODE FINDS
    // THE RESULT STRING USING DP[,]
    // Initialize result
    String res = "";
 
    // Traverse dp[,] from bottom right
    i = n; j= n;
    while (i > 0 && j > 0)
    {
        // If this cell is same as diagonally
        // adjacent cell just above it, then
        // same characters are present at
        // str[i-1] and str[j-1]. Append any
        // of them to result.
        if (dp[i, j] == dp[i - 1,j - 1] + 1)
        {
            res = res + str[i - 1];
            i--;
            j--;
        }
 
        // Otherwise we move to the side
        // that that gave us maximum result
        else if (dp[i,j] == dp[i - 1,j])
            i--;
        else
            j--;
    }
 
    // Since we traverse dp[,] from bottom,
    // we get result in reverse order.
    String reverse = "";
         
         
    for(int k = res.Length - 1; k >= 0; k--)
        {
            reverse = reverse + res[k];
        }
 
 
    return reverse;
}
 
// Driver code
public static void Main(String []args)
{
    String str = "AABEBCDD";
    Console.WriteLine(longestRepeatedSubSeq(str));
}
}
 
// This code is contributed by Princi Singh


时间复杂度: O(n ^ 2)
如何打印子序列?
上述解决方案仅找到子序列的长度。我们可以使用内置的dp [n + 1] [n + 1]表来打印子序列。这个想法类似于打印LCS。

// Pseudo code to find longest repeated
// subsequence using the dp[][] table filled
// above.

// Initialize result
string res = "";

// Traverse dp[][] from bottom right
i = n, j = n;
while (i > 0 && j > 0)
{
   // If this cell is same as diagonally
   // adjacent cell just above it, then 
   // same characters are present at 
   // str[i-1] and str[j-1]. Append any 
   // of them to result.
   if (dp[i][j] == dp[i-1][j-1] + 1)
   {
       res = res + str[i-1];
       i--;
       j--;
   }

   // Otherwise we move to the side
   // that that gave us maximum result
   else if (dp[i][j] == dp[i-1][j])
      i--;
   else
      j--;
 }

 // Since we traverse dp[][] from bottom,
 // we get result in reverse order.
 reverse(res.begin(), res.end());

return res;

以下是上述步骤的实现。

C++

// C++ program to find the longest repeated
// subsequence
#include 
using namespace std;
 
// This function mainly returns LCS(str, str)
// with a condition that same characters at
// same index are not considered.
string longestRepeatedSubSeq(string str)
{
    // THIS PART OF CODE IS SAME AS BELOW POST.
    // IT FILLS dp[][]
    // https://www.geeksforgeeks.org/longest-repeating-subsequence/
    // OR the code mentioned above.
    int n = str.length();
    int dp[n+1][n+1];
    for (int i=0; i<=n; i++)
        for (int j=0; j<=n; j++)
            dp[i][j] = 0;
    for (int i=1; i<=n; i++)
        for (int j=1; j<=n; j++)
            if (str[i-1] == str[j-1] && i != j)
                dp[i][j] =  1 + dp[i-1][j-1];
            else
                dp[i][j] = max(dp[i][j-1], dp[i-1][j]);
 
 
    // THIS PART OF CODE FINDS THE RESULT STRING USING DP[][]
    // Initialize result
    string res = "";
 
    // Traverse dp[][] from bottom right
    int i = n, j = n;
    while (i > 0 && j > 0)
    {
        // If this cell is same as diagonally
        // adjacent cell just above it, then
        // same characters are present at
        // str[i-1] and str[j-1]. Append any
        // of them to result.
        if (dp[i][j] == dp[i-1][j-1] + 1)
        {
           res = res + str[i-1];
           i--;
           j--;
        }
 
        // Otherwise we move to the side
        // that that gave us maximum result
        else if (dp[i][j] == dp[i-1][j])
            i--;
        else
            j--;
    }
 
    // Since we traverse dp[][] from bottom,
    // we get result in reverse order.
    reverse(res.begin(), res.end());
 
    return res;
}
 
// Driver Program
int main()
{
    string str = "AABEBCDD";
    cout << longestRepeatedSubSeq(str);
    return 0;
}

Java

// Java program to find the longest repeated
// subsequence
import java.util.*;
 
class GFG
{
 
// This function mainly returns LCS(str, str)
// with a condition that same characters at
// same index are not considered.
static String longestRepeatedSubSeq(String str)
{
    // THIS PART OF CODE IS SAME AS BELOW POST.
    // IT FILLS dp[][]
    // https://www.geeksforgeeks.org/longest-repeating-subsequence/
    // OR the code mentioned above.
    int n = str.length();
    int[][] dp = new int[n + 1][n + 1];
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= n; j++)
            dp[i][j] = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (str.charAt(i - 1) == str.charAt(j - 1) && i != j)
                dp[i][j] = 1 + dp[i - 1][j - 1];
            else
                dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
 
 
    // THIS PART OF CODE FINDS
    // THE RESULT STRING USING DP[][]
    // Initialize result
    String res = "";
 
    // Traverse dp[][] from bottom right
    int i = n, j = n;
    while (i > 0 && j > 0)
    {
        // If this cell is same as diagonally
        // adjacent cell just above it, then
        // same characters are present at
        // str[i-1] and str[j-1]. Append any
        // of them to result.
        if (dp[i][j] == dp[i - 1][j - 1] + 1)
        {
        res = res + str.charAt(i - 1);
        i--;
        j--;
        }
 
        // Otherwise we move to the side
        // that that gave us maximum result
        else if (dp[i][j] == dp[i - 1][j])
            i--;
        else
            j--;
    }
 
    // Since we traverse dp[][] from bottom,
    // we get result in reverse order.
    String reverse = "";
         
         
    for(int k = res.length() - 1; k >= 0; k--)
        {
            reverse = reverse + res.charAt(k);
        }
 
 
    return reverse;
}
 
// Driver code
public static void main(String args[])
{
    String str = "AABEBCDD";
    System.out.println(longestRepeatedSubSeq(str));
}
}
 
// This code is contributed by
// Surendra_Gangwar

Python3

# Python3 program to find the
# longest repeated subsequence
 
# This function mainly returns LCS(str, str)
# with a condition that same characters
# at same index are not considered.
def longestRepeatedSubSeq(str):
    # This part of code is same as
    # below post it fills dp[][]
    # https://www.geeksforgeeks.org/longest-repeating-subsequence/
    # OR the code mentioned above
    n = len(str)
    dp = [[0 for i in range(n+1)] for j in range(n+1)]
     
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            if (str[i-1] == str[j-1] and i != j):
                dp[i][j] = 1 + dp[i-1][j-1]
            else:
                dp[i][j] = max(dp[i][j-1], dp[i-1][j])
 
    # This part of code finds the result
    # string using dp[][] Initialize result
    res = ''
 
    # Traverse dp[][] from bottom right
    i = n
    j = n
    while (i > 0 and j > 0):
        # If this cell is same as diagonally
        # adjacent cell just above it, then
        # same characters are present at
        # str[i-1] and str[j-1]. Append any
        # of them to result.
        if (dp[i][j] == dp[i-1][j-1] + 1):
            res += str[i-1]
            i -= 1
            j -= 1
 
        # Otherwise we move to the side
        # that gave us maximum result.
        elif (dp[i][j] == dp[i-1][j]):
            i -= 1
        else:
            j -= 1
 
    # Since we traverse dp[][] from bottom,
    # we get result in reverse order.
    res = ''.join(reversed(res))
     
    return res
     
# Driver Program
str = 'AABEBCDD'
print(longestRepeatedSubSeq(str))
 
# This code is contributed by Soumen Ghosh

的PHP

 0 && $j > 0)
    {
        // If this cell is same as diagonally
        // adjacent cell just above it, then
        // same characters are present at
        // str[i-1] and str[j-1]. Append any
        // of them to result.
        if ($dp[$i][$j] == $dp[$i - 1][$j - 1] + 1)
        {
            $res = $res.$str[$i - 1];
            $i--;
            $j--;
        }
 
        // Otherwise we move to the side
        // that that gave us maximum result
        else if ($dp[$i][$j] == $dp[$i - 1][$j])
            $i--;
        else
            $j--;
    }
 
    // Since we traverse dp[][] from bottom,
    // we get result in reverse order.
    return strrev($res) ;
}
 
// Driver Code
$str = "AABEBCDD";
echo longestRepeatedSubSeq($str);
 
// This code is contributed by Ryuga
?>

C#

// C# program to find the longest repeated
// subsequence
using System;
using System.Collections.Generic;
     
class GFG
{
 
// This function mainly returns LCS(str, str)
// with a condition that same characters at
// same index are not considered.
static String longestRepeatedSubSeq(String str)
{
    // THIS PART OF CODE IS SAME AS BELOW POST.
    // IT FILLS dp[,]
    // https://www.geeksforgeeks.org/longest-repeating-subsequence/
    // OR the code mentioned above.
    int n = str.Length,i,j;
    int[,] dp = new int[n + 1,n + 1];
    for (i = 0; i <= n; i++)
        for (j = 0; j <= n; j++)
            dp[i, j] = 0;
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            if (str[i - 1] == str[j - 1] && i != j)
                dp[i, j] = 1 + dp[i - 1, j - 1];
            else
                dp[i, j] = Math.Max(dp[i, j - 1], dp[i - 1, j]);
 
 
    // THIS PART OF CODE FINDS
    // THE RESULT STRING USING DP[,]
    // Initialize result
    String res = "";
 
    // Traverse dp[,] from bottom right
    i = n; j= n;
    while (i > 0 && j > 0)
    {
        // If this cell is same as diagonally
        // adjacent cell just above it, then
        // same characters are present at
        // str[i-1] and str[j-1]. Append any
        // of them to result.
        if (dp[i, j] == dp[i - 1,j - 1] + 1)
        {
            res = res + str[i - 1];
            i--;
            j--;
        }
 
        // Otherwise we move to the side
        // that that gave us maximum result
        else if (dp[i,j] == dp[i - 1,j])
            i--;
        else
            j--;
    }
 
    // Since we traverse dp[,] from bottom,
    // we get result in reverse order.
    String reverse = "";
         
         
    for(int k = res.Length - 1; k >= 0; k--)
        {
            reverse = reverse + res[k];
        }
 
 
    return reverse;
}
 
// Driver code
public static void Main(String []args)
{
    String str = "AABEBCDD";
    Console.WriteLine(longestRepeatedSubSeq(str));
}
}
 
// This code is contributed by Princi Singh

输出:

ABD