目录
零、综述
本文章使用四种不同的算法实现:
输入两个字符串 s1,s2�1,�2。
输出最长连续公共子串长度和最长连续公共子串。
原题
链接:https://www.acwing.com/problem/content/description/3695/
一、时间复杂度为O(n*4)的算法
使用四层循环,暴力枚举破解
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int main() {
string a, b;
cin >> a >> b;
string res;
for (int len = min(a.size(), b.size()); len; len--) {
for (int i = a.size() - len; i >= 0; i--) {
for (int j = b.size() - len; j >= 0; j--) {
string s1 = a.substr(i, len), s2 = b.substr(j, len);
if (s1 == s2) {
res = s1;
break;
}
}
if (res.size())break;
}
if (res.size())break;
}
cout << res.size() << endl;
cout << res << endl;
return 0;
}
二、时间复杂度为O(n*2)的算法
使用动态规划算法,
/*
* 有一种更高效的算法可以用于找到两个字符串的最长公共子串,称为动态规划算法。
* 动态规划算法的原理是利用一个二维数组来记录两个字符串的所有子串的公共长度。
假设a和b分别是两个字符串,dp[i][j]表示以a[i]和b[j]结尾的子串的最长公共长度。
则有以下递推关系:
* 如果a[i] == b[j],则dp[i][j] = dp[i-1][j-1] + 1;
* 如果a[i] != b[j],则dp[i][j] = 0。
* 最终,最长公共子串的长度就是dp数组中的最大值,而最长公共子串的内容可以通过回溯dp数组得到。
* 下面是使用动态规划算法实现找到两个字符串的最长公共子串的代码:
*
* 该算法的时间复杂度为O(m*n),其中m和n分别是两个字符串的长度。
*/
/*
* 有一种更高效的算法可以用于找到两个字符串的最长公共子串,称为动态规划算法。
* 动态规划算法的原理是利用一个二维数组来记录两个字符串的所有子串的公共长度。
假设a和b分别是两个字符串,dp[i][j]表示以a[i]和b[j]结尾的子串的最长公共长度。
则有以下递推关系:
* 如果a[i] == b[j],则dp[i][j] = dp[i-1][j-1] + 1;
* 如果a[i] != b[j],则dp[i][j] = 0。
* 最终,最长公共子串的长度就是dp数组中的最大值,而最长公共子串的内容可以通过回溯dp数组得到。
* 下面是使用动态规划算法实现找到两个字符串的最长公共子串的代码:
*
* 该算法的时间复杂度为O(m*n),其中m和n分别是两个字符串的长度。
*/
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 110;
int main() {
string a, b;
cin >> a >> b;
int m = a.size(), n = b.size();
int dp[N][N]; // 定义dp数组,多加一行一列用于边界处理
memset(dp, 0, sizeof(dp)); // 初始化dp数组为0
int maxLen = 0; // 最长公共子串的长度
int endIdx = 0; // 最长公共子串的结束索引
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (a[i - 1] == b[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
if (dp[i][j] >= maxLen) {
maxLen = dp[i][j];
endIdx = i - 1; // 更新最长公共子串的结束索引
}
}
}
}
string res = a.substr(endIdx - maxLen + 1, maxLen); // 根据结束索引和最长公共子串的长度得到最长公共子串
cout << maxLen << endl; // 输出最长公共子串的长度
cout << res << endl; // 输出最长公共子串
return 0;
}
三、时间复杂度为O(n)的算法
// 时间复杂度为O(n)的算法
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
const int N = 105;
string longest_common_substring(string a, string b) {
int m = a.length(),n = b.length();
int maxLen = 0; // 最长公共子串的长度
int endIdx = 0; // 最长公共子串的结束索引
int dp[N][N] = { 0 }; // 定义dp数组,用于记录公共子串的长度
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (a[i - 1] == b[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
if (dp[i][j] >= maxLen) {
maxLen = dp[i][j];
endIdx = i - 1;
}
}
}
}
string longestSubstring = a.substr(endIdx - maxLen + 1, maxLen);
return longestSubstring;
}
int main() {
string a, b;
cin >> a >> b;
string longestSubstring = longest_common_substring(a, b);
cout << longestSubstring.size() << endl
<< longestSubstring << endl;
return 0;
}