题目:求两个字符串的最大公共子序列(可以不连续)的长度,并输出这个子序列。
例如:
输入 googleg和elgoog 输出 goog 4
输入 abcda和adcba 输出 aba 3
而为了得到相同的子序列,需要根据回溯路径,写出匹配字串,如下图,绿色的部分就是路径回溯的结果。
代码如下:
int SearchMaxLengthSequence(string s1, string s2)
{
int length1 = s1.length();
int length2 = s2.length();
int** matrix = new int*[length1 + 1];
for (size_t i = 0; i < length1 + 1; i++)
{
matrix[i] = new int[length2 + 1]();
}
for (size_t i = 1; i <= length1; i++)
{
for (size_t j = 1; j <= length2; j++)
{
if (s1[i - 1] == s2[j - 1])
{
matrix[i][j] = matrix[i - 1][j - 1] + 1;
}
else
{
matrix[i][j] = max(matrix[i][j - 1], matrix[i - 1][j]);
}
}
}
int commomLength = matrix[length1][length2];//最大子序列的长度
string commomStr = "";//保存逆序的子序列
//回溯部分
while (length1 != 0)
{
if (matrix[length1][length2] == matrix[length1 - 1][length2])
{
length1--;
continue;
}
if (matrix[length1][length2] == matrix[length1][length2 - 1])
{
length2--;
continue;
}
if (matrix[length1][length2] == matrix[length1 - 1][length2 - 1] + 1)
{
commomStr += s1[length1 - 1];
length1--;
length2--;
}
}
reverse(commomStr.begin(), commomStr.end());
cout << commomStr << endl;
return commomLength;
}
扩展:求字符串中回文字符串的个数
形式和前面那个类似,关键问题就是转移矩阵的确定:
定义dp [i][j]:表示字符串序列A的前i个字符组成的序列Ax和字符串序列B的前j个字符组成的序列By之间的公共子序列的个数(m ,n分别为Ax和By的长度,i<=m,j<=n)
状态转移方程:
if Ax[i] != By[j] 则有 dp[i][j] = dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1]
else dp[i][j]=dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1]+dp[i+1][j-1]+1=dp[i+1][j] + dp[i][j-1]+1
其中序列str:[0][1][2]……[i][i+1]…….[j-1][j]……
代码:
int NumOfSubPlalindrome(string str)
{
int len = str.length();
if (len == 0)
return 0;
vector<vector<int> > dp(len, vector<int>(len));//对此只进行了一半的使用
for (int j = 0; j < len; j++)
{
dp[j][j] = 1;
for (int i = j - 1; i >= 0; i--)
{
dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1];
if (str[i] == str[j])
{
dp[i][j] += dp[i + 1][j - 1] + 1;
}
}
}
return dp[0][len - 1];//表示从0至len-1之间的回文个数
}