给定两个字符串“ X”和“ Y”,找到最长的公共子字符串的长度。
例子 :
Input : X = “GeeksforGeeks”, y = “GeeksQuiz”
Output : 5
Explanation:
The longest common substring is “Geeks” and is of length 5.
Input : X = “abcdxyz”, y = “xyzabcd”
Output : 4
Explanation:
The longest common substring is “abcd” and is of length 4.
Input : X = “zxabcdezy”, y = “yzabcdezx”
Output : 6
Explanation:
The longest common substring is “abcdez” and is of length 6.
方法:
令m和n分别为第一和第二字符串的长度。
一个简单的解决方案是一个一个地考虑第一个字符串的所有子字符串,并为每个子字符串检查它是否是第二个字符串的子字符串。跟踪最大长度的子字符串。将有O(m ^ 2)个子字符串,我们可以找到一个字符串是否在O(n)时间内在另一个字符串进行替换(请参见此内容)。因此,此方法的整体时间复杂度为O(n * m 2 )
动态编程可用于查找O(m * n)时间中最长的公共子字符串。这个想法是找到两个字符串的所有子字符串的最长公共后缀的长度,并将这些长度存储在一个表中。
The longest common suffix has following optimal substructure property.
If last characters match, then we reduce both lengths by 1
LCSuff(X, Y, m, n) = LCSuff(X, Y, m-1, n-1) + 1 if X[m-1] = Y[n-1]
If last characters do not match, then result is 0, i.e.,
LCSuff(X, Y, m, n) = 0 if (X[m-1] != Y[n-1])
Now we consider suffixes of different substrings ending at different indexes.
The maximum length Longest Common Suffix is the longest common substring.
LCSubStr(X, Y, m, n) = Max(LCSuff(X, Y, i, j)) where 1 <= i <= m and 1 <= j <= n
以下是上述解决方案的迭代实现。
C++
/* Dynamic Programming solution to
find length of the
longest common substring */
#include
#include
using namespace std;
/* Returns length of longest
common substring of X[0..m-1]
and Y[0..n-1] */
int LCSubStr(char* X, char* Y, int m, int n)
{
// Create a table to store
// lengths of longest
// common suffixes of substrings.
// Note that LCSuff[i][j] contains
// length of longest common suffix
// of X[0..i-1] and Y[0..j-1].
int LCSuff[m + 1][n + 1];
int result = 0; // To store length of the
// longest common substring
/* Following steps build LCSuff[m+1][n+1] in
bottom up fashion. */
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
// The first row and first column
// entries have no logical meaning,
// they are used only for simplicity
// of program
if (i == 0 || j == 0)
LCSuff[i][j] = 0;
else if (X[i - 1] == Y[j - 1]) {
LCSuff[i][j] = LCSuff[i - 1][j - 1] + 1;
result = max(result, LCSuff[i][j]);
}
else
LCSuff[i][j] = 0;
}
}
return result;
}
// Driver code
int main()
{
char X[] = "OldSite:GeeksforGeeks.org";
char Y[] = "NewSite:GeeksQuiz.com";
int m = strlen(X);
int n = strlen(Y);
cout << "Length of Longest Common Substring is "
<< LCSubStr(X, Y, m, n);
return 0;
}
Java
// Java implementation of
// finding length of longest
// Common substring using
// Dynamic Programming
class GFG {
/*
Returns length of longest common substring
of X[0..m-1] and Y[0..n-1]
*/
static int LCSubStr(char X[], char Y[],
int m, int n)
{
// Create a table to store
// lengths of longest common
// suffixes of substrings.
// Note that LCSuff[i][j]
// contains length of longest
// common suffix of
// X[0..i-1] and Y[0..j-1].
// The first row and first
// column entries have no
// logical meaning, they are
// used only for simplicity of program
int LCStuff[][] = new int[m + 1][n + 1];
// To store length of the longest
// common substring
int result = 0;
// Following steps build
// LCSuff[m+1][n+1] in bottom up fashion
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
if (i == 0 || j == 0)
LCStuff[i][j] = 0;
else if (X[i - 1] == Y[j - 1])
{
LCStuff[i][j]
= LCStuff[i - 1][j - 1] + 1;
result = Integer.max(result,
LCStuff[i][j]);
}
else
LCStuff[i][j] = 0;
}
}
return result;
}
// Driver Code
public static void main(String[] args)
{
String X = "OldSite:GeeksforGeeks.org";
String Y = "NewSite:GeeksQuiz.com";
int m = X.length();
int n = Y.length();
System.out.println(LCSubStr(X.toCharArray(),
Y.toCharArray(), m,
n));
}
}
// This code is contributed by Sumit Ghosh
Python3
# Python3 implementation of Finding
# Length of Longest Common Substring
# Returns length of longest common
# substring of X[0..m-1] and Y[0..n-1]
def LCSubStr(X, Y, m, n):
# Create a table to store lengths of
# longest common suffixes of substrings.
# Note that LCSuff[i][j] contains the
# length of longest common suffix of
# X[0...i-1] and Y[0...j-1]. The first
# row and first column entries have no
# logical meaning, they are used only
# for simplicity of the program.
# LCSuff is the table with zero
# value initially in each cell
LCSuff = [[0 for k in range(n+1)] for l in range(m+1)]
# To store the length of
# longest common substring
result = 0
# Following steps to build
# LCSuff[m+1][n+1] in bottom up fashion
for i in range(m + 1):
for j in range(n + 1):
if (i == 0 or j == 0):
LCSuff[i][j] = 0
elif (X[i-1] == Y[j-1]):
LCSuff[i][j] = LCSuff[i-1][j-1] + 1
result = max(result, LCSuff[i][j])
else:
LCSuff[i][j] = 0
return result
# Driver Code
X = 'OldSite:GeeksforGeeks.org'
Y = 'NewSite:GeeksQuiz.com'
m = len(X)
n = len(Y)
print('Length of Longest Common Substring is',
LCSubStr(X, Y, m, n))
# This code is contributed by Soumen Ghosh
C#
// C# implementation of finding length of longest
// Common substring using Dynamic Programming
using System;
class GFG {
// Returns length of longest common
// substring of X[0..m-1] and Y[0..n-1]
static int LCSubStr(string X, string Y, int m, int n)
{
// Create a table to store lengths of
// longest common suffixes of substrings.
// Note that LCSuff[i][j] contains length
// of longest common suffix of X[0..i-1]
// and Y[0..j-1]. The first row and first
// column entries have no logical meaning,
// they are used only for simplicity of
// program
int[, ] LCStuff = new int[m + 1, n + 1];
// To store length of the longest common
// substring
int result = 0;
// Following steps build LCSuff[m+1][n+1]
// in bottom up fashion
for (int i = 0; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
if (i == 0 || j == 0)
LCStuff[i, j] = 0;
else if (X[i - 1] == Y[j - 1])
{
LCStuff[i, j]
= LCStuff[i - 1, j - 1] + 1;
result
= Math.Max(result, LCStuff[i, j]);
}
else
LCStuff[i, j] = 0;
}
}
return result;
}
// Driver Code
public static void Main()
{
String X = "OldSite:GeeksforGeeks.org";
String Y = "NewSite:GeeksQuiz.com";
int m = X.Length;
int n = Y.Length;
Console.Write("Length of Longest Common"
+ " Substring is "
+ LCSubStr(X, Y, m, n));
}
}
// This code is contributed by Sam007.
PHP
Java
// Java implemenation of the above approach
import java.io.*;
class GFG
{
// Function to find the length of the
// longest LCS
static int LCSubStr(String s,String t,
int n,int m)
{
// Create DP table
int dp[][]=new int[2][m+1];
int res=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(s.charAt(i-1)==t.charAt(j-1))
{
dp[i%2][j]=dp[(i-1)%2][j-1]+1;
if(dp[i%2][j]>res)
res=dp[i%2][j];
}
else dp[i%2][j]=0;
}
}
return res;
}
// Driver Code
public static void main (String[] args)
{
String X="OldSite:GeeksforGeeks.org";
String Y="NewSite:GeeksQuiz.com";
int m=X.length();
int n=Y.length();
// Function call
System.out.println(LCSubStr(X,Y,m,n));
}
}
Python3
# Python implemenation of the above approach
# Function to find the length of the
# longest LCS
def LCSubStr(s, t, n, m):
# Create DP table
dp = [[0 for i in range(m + 1)] for j in range(2)]
res = 0
for i in range(n + 1):
for j in range(m + 1):
if(s[i - 1] == t[j - 1]):
dp[i % 2][j] = dp[(i - 1) % 2][j - 1] + 1
if(dp[i % 2][j] > res):
res = dp[i % 2][j]
else:
dp[i % 2][j] = 0
return res
# Driver Code
X = "OldSite:GeeksforGeeks.org"
Y = "NewSite:GeeksQuiz.com"
m = len(X)
n = len(Y)
# Function call
print(LCSubStr(X,Y,m,n))
# This code is contributed by avanitrachhadiya2155
C#
// C# implemenation of the above approach
using System;
public class GFG
{
// Function to find the length of the
// longest LCS
static int LCSubStr(string s,string t,
int n,int m)
{
// Create DP table
int[,] dp = new int[2, m + 1];
int res = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if(s[i - 1] == t[j - 1])
{
dp[i % 2, j] = dp[(i - 1) % 2, j - 1] + 1;
if(dp[i % 2, j] > res)
res = dp[i % 2, j];
}
else dp[i % 2, j] = 0;
}
}
return res;
}
// Driver Code
static public void Main (){
string X = "OldSite:GeeksforGeeks.org";
string Y = "NewSite:GeeksQuiz.com";
int m = X.Length;
int n = Y.Length;
// Function call
Console.WriteLine(LCSubStr(X,Y,m,n));
}
}
// This code is contributed by rag2127
C++
// C++ program using to find length of the
// longest common substring recursion
#include
using namespace std;
string X, Y;
// Returns length of function f
// or longest common substring
// of X[0..m-1] and Y[0..n-1]
int lcs(int i, int j, int count)
{
if (i == 0 || j == 0)
return count;
if (X[i - 1] == Y[j - 1]) {
count = lcs(i - 1, j - 1, count + 1);
}
count = max(count,
max(lcs(i, j - 1, 0),
lcs(i - 1, j, 0)));
return count;
}
// Driver code
int main()
{
int n, m;
X = "abcdxyz";
Y = "xyzabcd";
n = X.size();
m = Y.size();
cout << lcs(n, m, 0);
return 0;
}
Java
// Java program using to find length of the
// longest common substring recursion
class GFG {
static String X, Y;
// Returns length of function
// for longest common
// substring of X[0..m-1] and Y[0..n-1]
static int lcs(int i, int j, int count)
{
if (i == 0 || j == 0)
{
return count;
}
if (X.charAt(i - 1)
== Y.charAt(j - 1))
{
count = lcs(i - 1, j - 1, count + 1);
}
count = Math.max(count,
Math.max(lcs(i, j - 1, 0),
lcs(i - 1, j, 0)));
return count;
}
// Driver code
public static void main(String[] args)
{
int n, m;
X = "abcdxyz";
Y = "xyzabcd";
n = X.length();
m = Y.length();
System.out.println(lcs(n, m, 0));
}
}
// This code is contributed by Rajput-JI
Python3
# Python3 program using to find length of
# the longest common substring recursion
# Returns length of function for longest
# common substring of X[0..m-1] and Y[0..n-1]
def lcs(i, j, count):
if (i == 0 or j == 0):
return count
if (X[i - 1] == Y[j - 1]):
count = lcs(i - 1, j - 1, count + 1)
count = max(count, max(lcs(i, j - 1, 0),
lcs(i - 1, j, 0)))
return count
# Driver code
if __name__ == "__main__":
X = "abcdxyz"
Y = "xyzabcd"
n = len(X)
m = len(Y)
print(lcs(n, m, 0))
# This code is contributed by Ryuga
C#
// C# program using to find length
// of the longest common substring
// recursion
using System;
class GFG {
static String X, Y;
// Returns length of function for
// longest common substring of
// X[0..m-1] and Y[0..n-1]
static int lcs(int i, int j, int count)
{
if (i == 0 || j == 0) {
return count;
}
if (X[i - 1] == Y[j - 1]) {
count = lcs(i - 1, j - 1, count + 1);
}
count = Math.Max(count, Math.Max(lcs(i, j - 1, 0),
lcs(i - 1, j, 0)));
return count;
}
// Driver code
public static void Main()
{
int n, m;
X = "abcdxyz";
Y = "xyzabcd";
n = X.Length;
m = Y.Length;
Console.Write(lcs(n, m, 0));
}
}
// This code is contributed by Rajput-JI
PHP
Javascript
Python3
# Python code for the above approach
from functools import lru_cache
from operator import itemgetter
def longest_common_substring(x: str, y: str) -> (int, int, int):
# function to find the longest common substring
# Memorizing with maximum size of the memory as 1
@lru_cache(maxsize=1)
# function to find the longest common prefix
def longest_common_prefix(i: int, j: int) -> int:
if 0 <= i < len(x) and 0 <= j < len(y) and x[i] == y[j]:
return 1 + longest_common_prefix(i + 1, j + 1)
else:
return 0
# digonally computing the subproplems
# to decrease memory dependency
def digonal_computation():
# upper right trianle of the 2D array
for k in range(len(x)):
yield from ((longest_common_prefix(i, j), i, j)
for i, j in zip(range(k, -1, -1),
range(len(y) - 1, -1, -1)))
# lower left triangle of the 2D array
for k in range(len(y)):
yield from ((longest_common_prefix(i, j), i, j)
for i, j in zip(range(k, -1, -1),
range(len(x) - 1, -1, -1)))
# returning the maximum of all the subproblems
return max(digonal_computation(), key=itemgetter(0), default=(0, 0, 0))
# Driver Code
if __name__ == '__main__':
x: str = 'GeeksforGeeks'
y: str = 'GeeksQuiz'
length, i, j = longest_common_substring(x, y)
print(f'length: {length}, i: {i}, j: {j}')
print(f'x substring: {x[i: i + length]}')
print(f'y substring: {y[j: j + length]}')
Length of Longest Common Substring is 10
时间复杂度: O(m * n)
辅助空间: O(m * n)
另一种方法:(空间优化方法)。
在上述方法中,我们仅使用2-D数组的最后一行,因此我们可以通过使用来优化空间
尺寸为2 *(min(n,m))的二维数组。
下面是上述方法的实现:
Java
// Java implemenation of the above approach
import java.io.*;
class GFG
{
// Function to find the length of the
// longest LCS
static int LCSubStr(String s,String t,
int n,int m)
{
// Create DP table
int dp[][]=new int[2][m+1];
int res=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(s.charAt(i-1)==t.charAt(j-1))
{
dp[i%2][j]=dp[(i-1)%2][j-1]+1;
if(dp[i%2][j]>res)
res=dp[i%2][j];
}
else dp[i%2][j]=0;
}
}
return res;
}
// Driver Code
public static void main (String[] args)
{
String X="OldSite:GeeksforGeeks.org";
String Y="NewSite:GeeksQuiz.com";
int m=X.length();
int n=Y.length();
// Function call
System.out.println(LCSubStr(X,Y,m,n));
}
}
Python3
# Python implemenation of the above approach
# Function to find the length of the
# longest LCS
def LCSubStr(s, t, n, m):
# Create DP table
dp = [[0 for i in range(m + 1)] for j in range(2)]
res = 0
for i in range(n + 1):
for j in range(m + 1):
if(s[i - 1] == t[j - 1]):
dp[i % 2][j] = dp[(i - 1) % 2][j - 1] + 1
if(dp[i % 2][j] > res):
res = dp[i % 2][j]
else:
dp[i % 2][j] = 0
return res
# Driver Code
X = "OldSite:GeeksforGeeks.org"
Y = "NewSite:GeeksQuiz.com"
m = len(X)
n = len(Y)
# Function call
print(LCSubStr(X,Y,m,n))
# This code is contributed by avanitrachhadiya2155
C#
// C# implemenation of the above approach
using System;
public class GFG
{
// Function to find the length of the
// longest LCS
static int LCSubStr(string s,string t,
int n,int m)
{
// Create DP table
int[,] dp = new int[2, m + 1];
int res = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if(s[i - 1] == t[j - 1])
{
dp[i % 2, j] = dp[(i - 1) % 2, j - 1] + 1;
if(dp[i % 2, j] > res)
res = dp[i % 2, j];
}
else dp[i % 2, j] = 0;
}
}
return res;
}
// Driver Code
static public void Main (){
string X = "OldSite:GeeksforGeeks.org";
string Y = "NewSite:GeeksQuiz.com";
int m = X.Length;
int n = Y.Length;
// Function call
Console.WriteLine(LCSubStr(X,Y,m,n));
}
}
// This code is contributed by rag2127
10
时间复杂度: O(n * m)
辅助空间: O(min(m,n))
另一种方法:(使用递归)
这是上述方法的递归解决方案。
C++
// C++ program using to find length of the
// longest common substring recursion
#include
using namespace std;
string X, Y;
// Returns length of function f
// or longest common substring
// of X[0..m-1] and Y[0..n-1]
int lcs(int i, int j, int count)
{
if (i == 0 || j == 0)
return count;
if (X[i - 1] == Y[j - 1]) {
count = lcs(i - 1, j - 1, count + 1);
}
count = max(count,
max(lcs(i, j - 1, 0),
lcs(i - 1, j, 0)));
return count;
}
// Driver code
int main()
{
int n, m;
X = "abcdxyz";
Y = "xyzabcd";
n = X.size();
m = Y.size();
cout << lcs(n, m, 0);
return 0;
}
Java
// Java program using to find length of the
// longest common substring recursion
class GFG {
static String X, Y;
// Returns length of function
// for longest common
// substring of X[0..m-1] and Y[0..n-1]
static int lcs(int i, int j, int count)
{
if (i == 0 || j == 0)
{
return count;
}
if (X.charAt(i - 1)
== Y.charAt(j - 1))
{
count = lcs(i - 1, j - 1, count + 1);
}
count = Math.max(count,
Math.max(lcs(i, j - 1, 0),
lcs(i - 1, j, 0)));
return count;
}
// Driver code
public static void main(String[] args)
{
int n, m;
X = "abcdxyz";
Y = "xyzabcd";
n = X.length();
m = Y.length();
System.out.println(lcs(n, m, 0));
}
}
// This code is contributed by Rajput-JI
Python3
# Python3 program using to find length of
# the longest common substring recursion
# Returns length of function for longest
# common substring of X[0..m-1] and Y[0..n-1]
def lcs(i, j, count):
if (i == 0 or j == 0):
return count
if (X[i - 1] == Y[j - 1]):
count = lcs(i - 1, j - 1, count + 1)
count = max(count, max(lcs(i, j - 1, 0),
lcs(i - 1, j, 0)))
return count
# Driver code
if __name__ == "__main__":
X = "abcdxyz"
Y = "xyzabcd"
n = len(X)
m = len(Y)
print(lcs(n, m, 0))
# This code is contributed by Ryuga
C#
// C# program using to find length
// of the longest common substring
// recursion
using System;
class GFG {
static String X, Y;
// Returns length of function for
// longest common substring of
// X[0..m-1] and Y[0..n-1]
static int lcs(int i, int j, int count)
{
if (i == 0 || j == 0) {
return count;
}
if (X[i - 1] == Y[j - 1]) {
count = lcs(i - 1, j - 1, count + 1);
}
count = Math.Max(count, Math.Max(lcs(i, j - 1, 0),
lcs(i - 1, j, 0)));
return count;
}
// Driver code
public static void Main()
{
int n, m;
X = "abcdxyz";
Y = "xyzabcd";
n = X.Length;
m = Y.Length;
Console.Write(lcs(n, m, 0));
}
}
// This code is contributed by Rajput-JI
的PHP
Java脚本
4
最大空间优化:
- 在这种方法中,我们将使用递归来查找所有可能子串的最长前缀。
- 让给出最长公共后缀的长度,分别从字符串X , Y的索引i , j开始。
- 然后可以将该函数定义为:
- 在此递归中,我们可以看到该函数仅具有一个依赖性,因此这意味着如果我们按特定顺序进行计算,则可以只记住先前的计算。
- 请考虑下表,其中存储了解决方案:
0 | 1 | 2 | 3 | 4 | |
0 | |||||
1 | |||||
2 | |||||
3 |
我们需要对角向上找到解决方案。在此特定示例中:
- 第一个对角线
- (4,0)
- 第二对角线
- (4,1)
- (3,0)
- 第三对角线
- (4,2)
- (3,1)
- (2,0)
- …
这样,我们只需要记住先前的计算即可。
Python3
# Python code for the above approach
from functools import lru_cache
from operator import itemgetter
def longest_common_substring(x: str, y: str) -> (int, int, int):
# function to find the longest common substring
# Memorizing with maximum size of the memory as 1
@lru_cache(maxsize=1)
# function to find the longest common prefix
def longest_common_prefix(i: int, j: int) -> int:
if 0 <= i < len(x) and 0 <= j < len(y) and x[i] == y[j]:
return 1 + longest_common_prefix(i + 1, j + 1)
else:
return 0
# digonally computing the subproplems
# to decrease memory dependency
def digonal_computation():
# upper right trianle of the 2D array
for k in range(len(x)):
yield from ((longest_common_prefix(i, j), i, j)
for i, j in zip(range(k, -1, -1),
range(len(y) - 1, -1, -1)))
# lower left triangle of the 2D array
for k in range(len(y)):
yield from ((longest_common_prefix(i, j), i, j)
for i, j in zip(range(k, -1, -1),
range(len(x) - 1, -1, -1)))
# returning the maximum of all the subproblems
return max(digonal_computation(), key=itemgetter(0), default=(0, 0, 0))
# Driver Code
if __name__ == '__main__':
x: str = 'GeeksforGeeks'
y: str = 'GeeksQuiz'
length, i, j = longest_common_substring(x, y)
print(f'length: {length}, i: {i}, j: {j}')
print(f'x substring: {x[i: i + length]}')
print(f'y substring: {y[j: j + length]}')
length: 5, i: 0, j: 0
x substring: Geeks
y substring: Geeks
时间复杂度:
空间复杂度: