- 返回最长公共子序列的长度
leetcode 1143
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
m, n = len(text1), len(text2)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if text1[i - 1] == text2[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
return dp[-1][-1]
- 返回任意一个最长公共子序列
https://blog.csdn.net/jingjing_94/article/details/80539403
class Solution:
def LCS(self,s1,s2):
c = len(s1)+1
r = len(s2)+1
dp = [[0]*c for i in range(r)]
for i in range(1,r):
for j in range(1,c):
if s1[j-1] == s2[i-1]:
dp[i][j] = dp[i-1][j-1]+1
else:
dp[i][j] = max(dp[i-1][j],dp[i][j-1])
maxl = dp[-1][-1]
print(maxl)
# 生成最长公共子序列,只返回满足条件的一个
res = []
i = r-1
j = c-1
while i > 0 and j > 0:
if s1[j-1] == s2[i-1]:
res.append(s1[j-1])
i -= 1
j -= 1
else:
if dp[i-1][j] > dp[i][j-1]:
i -= 1
else:
j -= 1
return ''.join(res[::-1])
if __name__ == '__main__':
p = Solution()
a = input('enter s1:')
while a != 'e':
b = input('enter s2:')
print(p.LCS(a,b))
a = input('enter s1:')
- 返回所有可能的最长公共子序列集合
https://blog.csdn.net/zpalyq110/article/details/79994001
函数1)建立dp数组:c[ ][ ]数组记录字符相等数,遍历m*n次,判断字符是否一样,相等max(left,top)+1,不相等取max(left,top);同时填充d [][ ]数组,记录的是路径的方向,以便后面回溯出最长公共子序列,0、1、2、3分别代表lefttop、top、left、left==top。
函数2)回溯公共子串:需要定义一个**全局变量(class的全局变量,定义在所有函数之外)**来存放所有解,并且在分支前记录两个解的公共前缀。
#include <iostream>
#include<string>
#include<vector>
#include<set>
using namespace std;
// 全局变量
set<string> setOfLCS;
//建立dp数组:记录长度的数组c, 记录路径方向的数组d
int LCSlen(string str1, string str2, int **d) {
int len1 = str1.size();
int len2 = str2.size();
int **c = new int*[len1 + 1];//行数
for (int i = 0; i < len1 + 1; i++) {
c[i] = new int[len2 + 1];//列数
}
for (int i = 0; i < len1 + 1; i++)
c[i][0] = 0;
for (int i = 0; i < len2 + 1; i++)
c[0][i] = 0;
for (int i = 1; i < len1 + 1; i++)
{
for (int j = 1; j < len2 + 1; j++)
{
if (str1[i - 1] == str2[j - 1])//c的第i行元素对应str1的第i-1个元素
{
c[i][j] = c[i - 1][j - 1] + 1;
d[i][j] = 0; //方向 : lefttop
}
else if (c[i - 1][j] > c[i][j - 1])
{
c[i][j] = c[i - 1][j];
d[i][j] = 1; //方向 : top
}
else if (c[i - 1][j] < c[i][j - 1])
{
c[i][j] = c[i][j - 1];
d[i][j] = 2; //方向 : left
}
else
{
c[i][j] = c[i][j - 1];
d[i][j] = 3; //方向 :top==left
}
}
}
return c[len1][len2];
}
// 回溯最长公共子串
void PrintLCS(int **d, string str1, string lcs, int i, int j)
// 在分支前记录两个解的公共前缀
{
while (i >0 && j >0){
if (d[i][j] == 0)
{
string ss;
ss = str1[i - 1];
lcs.insert(0, ss);
i--;
j--;
}
else if (d[i][j] == 1)
i -- ;// top
else if(d[i][j] == 2)
j --; // left
else
{ //一旦有两条路可回溯,递归的分别回溯他们
PrintLCS(d, str1, lcs, i - 1, j);
PrintLCS(d, str1, lcs, i , j - 1);
return;
}
}
// 存入最长公共子串集合中
setOfLCS.insert(lcs);
}
// 主程序,负责调用函数,打印结果
int main() {
string str1, str2;
cout << "请输入第一个字符串:" << endl;
cin >> str1;
cout << "请输入第二个字符串:" << endl;
cin >> str2;
//str1 = "ABCBDAB";
//str2 = "BDCABA";
int len1 = str1.size();
int len2 = str2.size();
int **d = new int*[len1 + 1];//行数
for (int i = 0; i < len1 + 1; i++) {
d[i] = new int[len2 + 1];//列数
}
int len = LCSlen(str1, str2, d);
cout << "最长公共子序列的长度为:" << len << endl;
cout << "最长公共子序列为:" << endl;
string lcs;
PrintLCS(d, str1, lcs,len1, len2);
// set<string>::iterator返回一个指向集合的第一个元素的迭代器
set<string>::iterator beg = setOfLCS.begin();
for (; beg != setOfLCS.end(); ++beg)
cout << *beg << endl;
system("pause");
return 0;
}