题目描述:
给出两个字符串长度均为 $ 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; } };
|