暴力解法
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
string a, b, minn = "";
// a和b是我们输入的
// minn存储的是我们最小的那个字符串
string cut(int l, int r) {
string tmp = "";
for (int i = l; i <= r; i++) tmp += a[i];
return tmp;
}
// l代表的左端点,r代表的右端点,然后我们把这段的a截取出来
void solve() {
if (a.size() > b.size()) swap(a, b);
// 我们让较短的那个字符串是a
for (int i = 0; i < a.size(); i++) {
// 这个让a的左端点从a的每一个位置开始枚举
for (int j = i; j < a.size(); j++) {
// 这个是枚举a字符串截取的右端点
string tmp = cut(i, j);
// 获取我们截取出来的字符串
if (b.find(tmp) != string::npos)
if (tmp.size() > minn.size()) minn = tmp;
// 如果b中有截取出来的这个字符串,那么我们就是会比较和我们之前
// 保存的最长长度字符串比较,一样的不更新,因为要保证我们取到
// 第一个最长的,然后大于的时候进行一个更新
}
}
cout << minn << "\n";
// 输出我们最小的那个字符串
}
signed main() {
while(cin >> a >> b) {
minn = "";
// 因为多组输入,所以我们要进行这样一个清空的操作
solve();
}
return 0;
}
动态规划
思路:其实这个就是一个经典的DP问题,那我们最简单的思路其实就是我们可以开一个二维数组,那么我们这个二维数组是什么呢?假设我们定义了一个二维数组𝑑𝑝[𝑖][𝑗]dp[i][j],是什么意思呢?就是代表我们a字符串的前i个字符和b的前j的字符是一样的。
然后相同的地方设置为1,不同的地方设置为0,然后我们最后就是找最长的连续的对角线的长度就是最长的公共子串了
然后我们的状态转移方程就是:
#include <iostream>
using namespace std;
string substrMax(string a,string b)
{
if(a.size()>b.size())
{
swap(a,b);
}
int len1=a.size();//这里其实用m,n来命名会更加方便
int len2=b.size();
int dp[len1+1][len2+1];//dp[i][j]表示a的前i个字符和b的前j个字符的最长公共子串长度
int maxlen=0,end=0;
for(int i=0;i<=len1;++i)dp[i][0]=0;
for(int j=0;j<=len2;++j)dp[0][j]=0;
for(int i=1;i<=len1;++i)
{
for(int j=1;j<=len2;++j)
{
if(a[i-1]==b[j-1])dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=0;
if(dp[i][j]>maxlen)
{
maxlen=dp[i][j];
end=i-1;
}
}
}
if(maxlen==0)return "-1";
else return a.substr(end-maxlen+1,maxlen);
}
int main() {
string a,b;
cin>>a>>b;
cout<<substrMax(a,b);
return 0;
}