0%

1092.最短公共超序列

1092.最短公共超序列

题目描述:

给出两个字符串长度均为 $ n $ ,返回同时以 str1,str2为子序列的最短字符串。返回任意一个。子序列不连续。

数据范围:
$ 1\le n \le 1000 $

题解:

首先可以得到最长公共子序列,然后将每个字符串除了公共子序列外的字符按照顺序加入答案。

最长公共子序列

寻找dp路径时,需要从结果往前找。

如果 $ str1[i]==str2[j] $ 则 $ i—,j— $

否则 如果 $ dp[i][j]==dp[i-1][j] $ ,则 $ i— $

​ 否则 $ j— $ ;

1
2
3
4
5
6
7
8
9
10
if(str1[i]==str2[j])
{
i--;
j--;
}
else
{
if(dp[i][j] == dp[i-1][j]) i--;
else j--;
}

注意dp时候的下标问题,可以直接从 $ 1,n $ 枚举,只有在判断字符的时候转化为字符串的下标。也可以用 $ i + 1, j + 1 $ 替换递推方程中的 $ i,j $ 。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class Solution
{
public:
const static int maxn = 1e3 + 1;
const static int maxm = 1e5 + 1;
const static int INF = 0x3f3f3f3f;
int dp[maxn][maxn] = {};
string shortestCommonSupersequence(string str1, string str2)
{
int n = str1.length(), m = str2.length();
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
if (str1[i - 1] == str2[j - 1])
{
dp[i][j] = dp[i - 1][j - 1] + 1;
}
else
{
if (dp[i][j - 1] > dp[i - 1][j])
{
dp[i][j] = dp[i][j - 1];
}
else
{
dp[i][j] = dp[i - 1][j];
}
}
}
}
string ans;
int l1 = n, l2 = m;
while (l1 && l2)
{
if (str1[l1 - 1] == str2[l2 - 1])
{
ans = str1[l1 - 1] + ans;
l1--;
l2--;
}
else
{
if (dp[l1][l2] == dp[l1][l2 - 1])
{
ans = str2[l2 - 1] + ans;
l2--;
}
else
{
ans = str1[l1 - 1] + ans;
l1--;
}
}
}
if (l1)
ans = str1.substr(0, l1) + ans;
if (l2)
ans = str2.substr(0, l2) + ans;
return ans;
}
};