*description:最長公共子串
* 給定兩個字符串str1和str2,返回兩個字符串的最長公共子串
* 如:str1=“1AB2345CD” str2=“12345EF”
* 返回“2345”
***********************************************************************/
#include <iostream>
#include <string>
#include <vector>
using namespace std;
//方法1:時間複雜度O(M*N),空間複雜度O(M*N)
//經典動態規劃問題,數組dp[M][N]
//dp[i][j]代表str1[i]和str2[j]當做公共子串最後元素的最大長度
//dp[i][0]:str1[i]==str2[0]時才爲1,否則爲0
//dp[0][j]:str1[0]==str2[j]時才爲1,否則爲0
//dp[i][j]:
// 1.str1[i]!=str2[j],dp[i][j]=0
// 2.str1[i]==str2[j],dp[i][j]=dp[i-1][j-1]+1
//得到dp之後,遍歷找到最大的元素及其位置,然後str1的該位置向前索引即可。
string longestSharedSubStr_1(string str1, string str2)
{
string res;
int M = str1.size();
int N = str2.size();
if (M == 0 || N == 0)
return res;
vector<vector<int>> dp(M,N);
for (int i = 0; i < M; i++)
{
dp[i][0] = 0;
if (str1[i] == str2[0])
dp[i][0] = 1;
}
for (int j = 0; j < N; j++)
{
dp[0][j] = 0;
if (str1[0] == str2[j])
dp[0][j] = 1;
}
for (int i = 1; i < M; i++)
{
for (int j = 1; j < N; j++)
{
if (str1[i] != str2[j])
dp[i][j] = 0;
else
dp[i][j] = dp[i-1][j-1] + 1;
}
}
int len = 0;
int endIdx = 0;
for (int i = 0; i < M - 1; i++)
{
for (int j = 0; j < N; j++)
{
if (dp[i][j] > len)
{
len = dp[i][j];
endIdx = i;
}
}
}
return str1.substr(endIdx - len + 1, len);
}
//方法2:時間複雜度O(M*N),空間複雜度O(1)
//在方法1的基礎上進行優化。
//每次計算dp[i][j]時,只和dp[i-1][j-1]相關,所以每次按斜線計算,只用一個變量空間。
//然後用個全局變量記錄len和endIdx
string longestSharedSubStr_2(string str1, string str2)
{
int M = str1.size();
int N = str2.size();
if (M == 0 || N == 0)
return "";
int len = 0;
int endIdx = 0;
int last = 0;
int col = N -1;
int row = 0;
while (row < M)
{
last = 0;
int i = row;
int j = col;
while (i < M && j < N)
{
if (str1[i] == str2[j])
{
last++;
}
if (last > len )
{
len = last;
endIdx = i;
}
i++;
j++;
}
if (col > 0)
col--;
else
row++;
}
return str1.substr(endIdx - len + 1, len);
}
int main()
{
string str1 = "1AB2345CD";
string str2 = "12345EF";
cout << longestSharedSubStr_2(str1, str2);
return 0;
}