给定两个字符串X和Y 。任务是找到字符串X 的最长子序列的长度,它是序列 Y 中的子字符串。
例子:
Input : X = "ABCD", Y = "BACDBDCD"
Output : 3
"ACD" is longest subsequence of X which
is substring of Y.
Input : X = "A", Y = "A"
Output : 1
先决条件:最长公共子序列问题将帮助您快速理解这个问题🙂
方法一(蛮力):
使用蛮力查找 X 的所有子序列,并为每个子序列检查它是否是 Y 的子串。如果是Y的子串,保持一个最大长度变量,比较它的长度。
时间复杂度:O(2^n)
方法二:(递归):
设 n 为 X 的长度,m 为 Y 的长度。我们将创建一个递归函数,如下所示,有 4 个参数,返回类型为 int,因为我们将得到 X 的最大可能子序列的长度,即 Y 的子串。我们将根据字符串的最后一个字符使用 n-1 和 m-1 判断进一步处理。
int maxSubsequenceSubstring(string &X,string &Y,int n,int m)
{
....
return ans;
}
对于递归,我们需要两件事,我们将使第一个是基本情况,第二个是对较小输入的调用(为此我们将看到选择图)。
基本情况:
通过查看函数的参数,我们可以看到只有 2 个参数会在递归调用时发生变化,即两个字符串的长度。因此,对于基本情况,请考虑我们可以提供的最小输入。你会看到最小的输入是 0,即空长度。因此,当 n == 0 或 m == 0 是基本情况。 n 和 m 不能小于零。现在我们知道了条件,我们需要根据问题返回子序列的长度。如果长度为0,则表示其中一个字符串为空,并且没有可能的公共子序列,因此我们必须返回0。
int maxSubsequenceSubstring(string &X,string &Y,int n,int m)
{
if (n==0 || m==0) return 0;
....
return ans;
}
儿童电话:
我们可以通过查看两个字符串的最后一个字符是否相同来了解如何进行调用。我们可以看到这与 LCS(最长公共子序列)问题略有不同。
int maxSubsequenceSubstring(string &X,string &Y,int n,int m)
{
// Base Case
if (n==0 || m==0) return 0;
// Calls on smaller inputs
// if the last char of both strings are equal
if(X[n-1] == Y[m-1])
{
return 1 + maxSubsequenceSubstring(X,Y,n-1,m-1);
}
// if the last char of both strings are not equal
else
{
return maxSubsequenceSubstring(X,Y,n-1,m);
}
}
现在这里是问题的主要症结,我们可以看到我们正在调用 X[0..n] 和 Y[0..m],在我们的递归函数,它将返回 X 子序列的最大长度的答案, 和 Y 的子字符串(以及Y的该子字符串的结尾字符以长度 m 结尾)。这非常重要,因为我们也想找到所有中间子串。因此,我们需要使用 for 循环,在那里我们将对 Y 的从0 到 m的所有长度调用上述函数,并在那里返回答案的最大值。这是 C++ 中的最终代码。
C++
#include
using namespace std;
int maxSubsequenceSubstring(string &X,string &Y,int n,int m)
{
// Base Case
if (n==0 || m==0) return 0;
// Calls on smaller inputs
// if the last char of both strings are equal
if(X[n-1] == Y[m-1])
{
return 1 + maxSubsequenceSubstring(X,Y,n-1,m-1);
}
// if the last char of both strings are not equal
else
{
return maxSubsequenceSubstring(X,Y,n-1,m);
}
}
int main()
{
string X = "abcd";
string Y = "bacdbdcd";
int n = X.size(),m = Y.size();
int maximum_length = 0; //as minimum length can be 0 only.
for(int i = 0;i<=m;i++) // traversing for every length of Y.
{
int temp_ans = maxSubsequenceSubstring(X,Y,n,i);
if(temp_ans > maximum_length) maximum_length = temp_ans;
}
cout<<"Length for maximum possible Subsequence of string X which is Substring of Y -> "<
C++
#include
using namespace std;
int maxSubsequenceSubstring(string &X,string &Y,int n,int m,vector>& dp)
{
// Base Case
if (n==0 || m==0) return 0;
// check if we have already solved it?
if(dp[n][m] != -1) return dp[n][m];
// Calls on smaller inputs
// if the last char of both strings are equal
if(X[n-1] == Y[m-1])
{
return dp[n][m] = 1 + maxSubsequenceSubstring(X,Y,n-1,m-1,dp);
}
// if the last char of both strings are not equal
else
{
return dp[n][m] = maxSubsequenceSubstring(X,Y,n-1,m,dp);
}
}
int main()
{
string X = "abcd";
string Y = "bacdbdcd";
int n = X.size(),m = Y.size();
int maximum_length = 0; //as minimum length can be 0 only.
vector> dp(n+1,vector(m+1,-1));
for(int i = 0;i<=m;i++) // traversing for every length of Y.
{
int temp_ans = maxSubsequenceSubstring(X,Y,n,i,dp);
if(temp_ans > maximum_length) maximum_length = temp_ans;
}
cout<<"Length for maximum possible Subsequence of string X which is Substring of Y -> "<
Java
// Java program to find maximum length of
// subsequence of a string X such it is
// substring in another string Y.
public class GFG
{
static final int MAX = 1000;
// Return the maximum size of substring of
// X which is substring in Y.
static int maxSubsequenceSubstring(char x[], char y[],
int n, int m)
{
int dp[][] = new int[MAX][MAX];
// Initialize the dp[][] to 0.
for (int i = 0; i <= m; i++)
for (int j = 0; j <= n; j++)
dp[i][j] = 0;
// Calculating value for each element.
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
// If alphabet of string X and Y are
// equal make dp[i][j] = 1 + dp[i-1][j-1]
if (x[j - 1] == y[i - 1])
dp[i][j] = 1 + dp[i - 1][j - 1];
// Else copy the previous value in the
// row i.e dp[i-1][j-1]
else
dp[i][j] = dp[i][j - 1];
}
}
// Finding the maximum length.
int ans = 0;
for (int i = 1; i <= m; i++)
ans = Math.max(ans, dp[i][n]);
return ans;
}
// Driver Method
public static void main(String[] args)
{
char x[] = "ABCD".toCharArray();
char y[] = "BACDBDCD".toCharArray();
int n = x.length, m = y.length;
System.out.println(maxSubsequenceSubstring(x, y, n, m));
}
}
Python3
# Python3 program to find maximum
# length of subsequence of a string
# X such it is substring in another
# string Y.
MAX = 1000
# Return the maximum size of
# substring of X which is
# substring in Y.
def maxSubsequenceSubstring(x, y, n, m):
dp = [[0 for i in range(MAX)]
for i in range(MAX)]
# Initialize the dp[][] to 0.
# Calculating value for each element.
for i in range(1, m + 1):
for j in range(1, n + 1):
# If alphabet of string
# X and Y are equal make
# dp[i][j] = 1 + dp[i-1][j-1]
if(x[j - 1] == y[i - 1]):
dp[i][j] = 1 + dp[i - 1][j - 1]
# Else copy the previous value
# in the row i.e dp[i-1][j-1]
else:
dp[i][j] = dp[i][j - 1]
# Finding the maximum length
ans = 0
for i in range(1, m + 1):
ans = max(ans, dp[i][n])
return ans
# Driver Code
x = "ABCD"
y = "BACDBDCD"
n = len(x)
m = len(y)
print(maxSubsequenceSubstring(x, y, n, m))
# This code is contributed
# by sahilshelangia
C#
// C# program to find maximum length of
// subsequence of a string X such it is
// substring in another string Y.
using System;
public class GFG
{
static int MAX = 1000;
// Return the maximum size of substring of
// X which is substring in Y.
static int maxSubsequenceSubstring(string x, string y,
int n, int m)
{
int[ ,]dp = new int[MAX, MAX];
// Initialize the dp[][] to 0.
for (int i = 0; i <= m; i++)
for (int j = 0; j <= n; j++)
dp[i, j] = 0;
// Calculating value for each element.
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
// If alphabet of string X and Y are
// equal make dp[i][j] = 1 + dp[i-1][j-1]
if (x[j - 1] == y[i - 1])
dp[i, j] = 1 + dp[i - 1, j - 1];
// Else copy the previous value in the
// row i.e dp[i-1][j-1]
else
dp[i, j] = dp[i, j - 1];
}
}
// Finding the maximum length.
int ans = 0;
for (int i = 1; i <= m; i++)
ans = Math.Max(ans, dp[i,n]);
return ans;
}
// Driver Method
public static void Main()
{
string x = "ABCD";
string y = "BACDBDCD";
int n = x.Length, m = y.Length;
Console.WriteLine(maxSubsequenceSubstring(x,
y, n, m));
}
}
// This code is contributed by vt_m.
PHP
Javascript
Length for maximum possible Subsequence of string X which is Substring of Y -> 3
时间复杂度:O(n*m)(对于递归函数的每次调用,我们都在减少 n,因此我们将在 n 次调用之后恰好达到基本情况,并且我们针对字符串Y 的不同长度使用 for 循环 m 次)。
空间复杂度:O(n)(对于递归调用,我们为每次调用使用堆栈)。
方法三:(动态规划):
子方法 1:记忆
注意:必须查看上述递归解决方案才能将其优化理解为 Memoization
从上面的递归解决方案来看,有多个调用,进一步,我们在for循环中使用递归,很有可能我们已经解决了一个调用的答案。因此要优化我们将使用的递归解决方案? (请参阅我们在整个调用过程中只有 2 个不同的参数,因此数组的维数为 2,大小为因为我们需要存储来自 0..n 和 0..m 的所有可能调用的答案)。因此它是一个二维数组。
我们可以将向量用于数组的相同或动态分配。
// initialise a vector like this
vector> dp(n+1,vector(m+1,-1));
// or Dynamic allocation
int **dp = new int*[n+1];
for(int i = 0;i<=n;i++)
{
dp[i] = new int[m+1];
for(int j = 0;j<=m;j++)
{
dp[i][j] = -1;
}
}
通过初始化二维向量,我们将使用这个数组作为递归中的第 5 个参数并存储我们的答案。另外,我们用 -1 填充它,这意味着我们还没有解决这个调用,因此使用传统的递归,如果任何调用中的 dp[n][m] 不是 -1,意味着我们已经解决了这个调用,因此使用 dp[n][m] 的答案。
// In recursion calls we will check for if we have solved the answer for the call or not
if(dp[n][m] != -1) return dp[n][m];
// Else we will store the result and return that back from this call
if(X[n-1] == Y[m-1])
return dp[n][m] = 1 + maxSubsequenceSubstring(X,Y,n-1,m-1,dp);
else
return dp[n][m] = maxSubsequenceSubstring(X,Y,n-1,m,dp);
记忆代码在这里:
C++
#include
using namespace std;
int maxSubsequenceSubstring(string &X,string &Y,int n,int m,vector>& dp)
{
// Base Case
if (n==0 || m==0) return 0;
// check if we have already solved it?
if(dp[n][m] != -1) return dp[n][m];
// Calls on smaller inputs
// if the last char of both strings are equal
if(X[n-1] == Y[m-1])
{
return dp[n][m] = 1 + maxSubsequenceSubstring(X,Y,n-1,m-1,dp);
}
// if the last char of both strings are not equal
else
{
return dp[n][m] = maxSubsequenceSubstring(X,Y,n-1,m,dp);
}
}
int main()
{
string X = "abcd";
string Y = "bacdbdcd";
int n = X.size(),m = Y.size();
int maximum_length = 0; //as minimum length can be 0 only.
vector> dp(n+1,vector(m+1,-1));
for(int i = 0;i<=m;i++) // traversing for every length of Y.
{
int temp_ans = maxSubsequenceSubstring(X,Y,n,i,dp);
if(temp_ans > maximum_length) maximum_length = temp_ans;
}
cout<<"Length for maximum possible Subsequence of string X which is Substring of Y -> "<
Length for maximum possible Subsequence of string X which is Substring of Y -> 3
时间复杂度:O(n*m)(它肯定比递归解决方案更好,最坏的情况只有当字符串Y 中没有字符串X 的字符时才有可能。)
空间复杂度:O(n*m + n)(Dp数组的大小和递归的栈调用大小)
子方法 2:制表
令 n 为 X 的长度,m 为 Y 的长度。创建一个包含 m + 1 行和 n + 1 列的二维数组“dp[][]”。值dp[i][j]是 X[0….j] 的子序列的最大长度,它是 Y[0….i] 的子串。现在对于 dp[][] 的每个单元格填充值:
for (i = 1 to m)
for (j = 1 to n)
if (x[i-1] == y[j - 1])
dp[i][j] = dp[i-1][j-1] + 1;
else
dp[i][j] = dp[i][j-1];
最后,作为 y 子串的 x 的最长子序列的长度是 max(dp[i][n]) 其中 1 <= i <= m。
下面是实现这种方法:
C/C++
// C++ program to find maximum length of
// subsequence of a string X such it is
// substring in another string Y.
#include
#define MAX 1000
using namespace std;
// Return the maximum size of substring of
// X which is substring in Y.
int maxSubsequenceSubstring(char x[], char y[],
int n, int m)
{
int dp[MAX][MAX];
// Initialize the dp[][] to 0.
for (int i = 0; i <= m; i++)
for (int j = 0; j <= n; j++)
dp[i][j] = 0;
// Calculating value for each element.
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
// If alphabet of string X and Y are
// equal make dp[i][j] = 1 + dp[i-1][j-1]
if (x[j - 1] == y[i - 1])
dp[i][j] = 1 + dp[i - 1][j - 1];
// Else copy the previous value in the
// row i.e dp[i-1][j-1]
else
dp[i][j] = dp[i][j - 1];
}
}
// Finding the maximum length.
int ans = 0;
for (int i = 1; i <= m; i++)
ans = max(ans, dp[i][n]);
return ans;
}
// Driver Program
int main()
{
char x[] = "ABCD";
char y[] = "BACDBDCD";
int n = strlen(x), m = strlen(y);
cout << maxSubsequenceSubstring(x, y, n, m);
return 0;
}
时间复杂度:O(n*m)(填充 Dp 数组所需的时间)
空间复杂度:O(n*m + n)(Dp 数组的大小)
Java
// Java program to find maximum length of
// subsequence of a string X such it is
// substring in another string Y.
public class GFG
{
static final int MAX = 1000;
// Return the maximum size of substring of
// X which is substring in Y.
static int maxSubsequenceSubstring(char x[], char y[],
int n, int m)
{
int dp[][] = new int[MAX][MAX];
// Initialize the dp[][] to 0.
for (int i = 0; i <= m; i++)
for (int j = 0; j <= n; j++)
dp[i][j] = 0;
// Calculating value for each element.
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
// If alphabet of string X and Y are
// equal make dp[i][j] = 1 + dp[i-1][j-1]
if (x[j - 1] == y[i - 1])
dp[i][j] = 1 + dp[i - 1][j - 1];
// Else copy the previous value in the
// row i.e dp[i-1][j-1]
else
dp[i][j] = dp[i][j - 1];
}
}
// Finding the maximum length.
int ans = 0;
for (int i = 1; i <= m; i++)
ans = Math.max(ans, dp[i][n]);
return ans;
}
// Driver Method
public static void main(String[] args)
{
char x[] = "ABCD".toCharArray();
char y[] = "BACDBDCD".toCharArray();
int n = x.length, m = y.length;
System.out.println(maxSubsequenceSubstring(x, y, n, m));
}
}
蟒蛇3
# Python3 program to find maximum
# length of subsequence of a string
# X such it is substring in another
# string Y.
MAX = 1000
# Return the maximum size of
# substring of X which is
# substring in Y.
def maxSubsequenceSubstring(x, y, n, m):
dp = [[0 for i in range(MAX)]
for i in range(MAX)]
# Initialize the dp[][] to 0.
# Calculating value for each element.
for i in range(1, m + 1):
for j in range(1, n + 1):
# If alphabet of string
# X and Y are equal make
# dp[i][j] = 1 + dp[i-1][j-1]
if(x[j - 1] == y[i - 1]):
dp[i][j] = 1 + dp[i - 1][j - 1]
# Else copy the previous value
# in the row i.e dp[i-1][j-1]
else:
dp[i][j] = dp[i][j - 1]
# Finding the maximum length
ans = 0
for i in range(1, m + 1):
ans = max(ans, dp[i][n])
return ans
# Driver Code
x = "ABCD"
y = "BACDBDCD"
n = len(x)
m = len(y)
print(maxSubsequenceSubstring(x, y, n, m))
# This code is contributed
# by sahilshelangia
C#
// C# program to find maximum length of
// subsequence of a string X such it is
// substring in another string Y.
using System;
public class GFG
{
static int MAX = 1000;
// Return the maximum size of substring of
// X which is substring in Y.
static int maxSubsequenceSubstring(string x, string y,
int n, int m)
{
int[ ,]dp = new int[MAX, MAX];
// Initialize the dp[][] to 0.
for (int i = 0; i <= m; i++)
for (int j = 0; j <= n; j++)
dp[i, j] = 0;
// Calculating value for each element.
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
// If alphabet of string X and Y are
// equal make dp[i][j] = 1 + dp[i-1][j-1]
if (x[j - 1] == y[i - 1])
dp[i, j] = 1 + dp[i - 1, j - 1];
// Else copy the previous value in the
// row i.e dp[i-1][j-1]
else
dp[i, j] = dp[i, j - 1];
}
}
// Finding the maximum length.
int ans = 0;
for (int i = 1; i <= m; i++)
ans = Math.Max(ans, dp[i,n]);
return ans;
}
// Driver Method
public static void Main()
{
string x = "ABCD";
string y = "BACDBDCD";
int n = x.Length, m = y.Length;
Console.WriteLine(maxSubsequenceSubstring(x,
y, n, m));
}
}
// This code is contributed by vt_m.
PHP
Javascript
3
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。