1、解题思路
- 动态规划:定义 dp[i][j] 为 str1 的前 i 个字符和 str2 的前 j 个字符的最长公共子串的长度。递推关系:
如果 str1[i-1] == str2[j-1],则 dp[i][j] = dp[i-1][j-1] + 1。否则,dp[i][j] = 0。初始条件:dp[0][j] = 0 和 dp[i][0] = 0(表示空字符串的公共子串长度为 0)。
- 记录最大值和位置:在填充 dp 表格的同时,记录最大长度和对应的位置。
- 反向构造子串:根据记录的最大长度和位置,从 str1 或 str2 中提取最长公共子串。
2、代码实现
C++
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* longest common substring
* @param str1 string字符串 the string
* @param str2 string字符串 the string
* @return string字符串
*/
string LCS(string str1, string str2) {
// write code here
int m = str1.size(), n = str2.size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0)); // 空间 O(m × n)
int max_len = 0, pos = 0;
for (int i = 1; i <= m; ++i) { // 时间 O(m × n)
for (int j = 1; j <= n; ++j) {
if (str1[i - 1] == str2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
if (dp[i][j] > max_len) {
max_len = dp[i][j];
pos = i - 1;
}
}
}
}
if (max_len == 0) {
return "-1";
}
return str1.substr(pos - max_len + 1, max_len);
}
};
Java
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* longest common substring
* @param str1 string字符串 the string
* @param str2 string字符串 the string
* @return string字符串
*/
public String LCS (String str1, String str2) {
// write code here
int m = str1.length(), n = str2.length();
int[][] dp = new int[m + 1][n + 1]; // 空间 O(m × n)
int max_len = 0, pos = 0;
for (int i = 1; i <= m; ++i) { // 时间 O(m × n)
for (int j = 1; j <= n; ++j) {
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
if (dp[i][j] > max_len) {
max_len = dp[i][j];
pos = i - 1;
}
} else {
dp[i][j] = 0;
}
}
}
if (max_len == 0) return "-1";
return str1.substring(pos - max_len + 1, pos + 1);
}
}
3、复杂度分析
- 时间复杂度:O(m × n),其中
m
和 n
分别是 str1
和 str2
的长度。 - 空间复杂度:O(m × n),用于存储
dp
表格。