LeetCode 题解工作台
最短公共超序列
给你两个字符串 str1 和 str2 ,返回同时以 str1 和 str2 作为 子序列 的最短字符串。如果答案不止一个,则可以返回满足条件的 任意一个 答案。 如果从字符串 t 中删除一些字符(也可能不删除),可以得到字符串 s ,那么 s 就是 t 的一个子序列。 示例 1: 输入: str1…
2
题型
5
代码语言
3
相关题
当前训练重点
困难 · 状态·转移·动态规划
答案摘要
我们先用动态规划求出两个字符串的最长公共子序列,然后根据最长公共子序列构造出最短公共超序列。 定义 表示字符串 的前 个字符和字符串 的前 个字符的最长公共子序列的长度。状态转移方程如下:
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路
题目描述
给你两个字符串 str1 和 str2,返回同时以 str1 和 str2 作为 子序列 的最短字符串。如果答案不止一个,则可以返回满足条件的 任意一个 答案。
如果从字符串 t 中删除一些字符(也可能不删除),可以得到字符串 s ,那么 s 就是 t 的一个子序列。
示例 1:
输入:str1 = "abac", str2 = "cab" 输出:"cabac" 解释: str1 = "abac" 是 "cabac" 的一个子串,因为我们可以删去 "cabac" 的第一个 "c"得到 "abac"。 str2 = "cab" 是 "cabac" 的一个子串,因为我们可以删去 "cabac" 末尾的 "ac" 得到 "cab"。 最终我们给出的答案是满足上述属性的最短字符串。
示例 2:
输入:str1 = "aaaaaaaa", str2 = "aaaaaaaa" 输出:"aaaaaaaa"
提示:
1 <= str1.length, str2.length <= 1000str1和str2都由小写英文字母组成。
解题思路
方法一:动态规划 + 构造
我们先用动态规划求出两个字符串的最长公共子序列,然后根据最长公共子序列构造出最短公共超序列。
定义 表示字符串 的前 个字符和字符串 的前 个字符的最长公共子序列的长度。状态转移方程如下:
接下来我们基于 构造出最短公共超序列。
str1: a b a c
str2: c a b
ans: c a b a c
不妨对照着上面的示例字符串,来看看如何构造出最短公共超序列。
我们用双指针 和 分别指向字符串 和 的末尾,然后从后往前遍历,每次比较 和 的值:
- 如果 ,则将 或 中的任意一个字符加入到最答案序列的末尾,然后 和 同时减 ;
- 如果 ,则将 与 和 中的最大值进行比较:
- 如果 ,则将 加入到答案序列的末尾,然后 减 ;
- 如果 ,则将 加入到答案序列的末尾,然后 减 。
重复上述操作,直到 或 ,然后将剩余的字符串加入到答案序列的末尾即可。
最后我们将答案序列反转,即可得到最终的答案。
时间复杂度 ,空间复杂度 。其中 和 分别是字符串 和 的长度。
class Solution:
def shortestCommonSupersequence(self, str1: str, str2: str) -> str:
m, n = len(str1), len(str2)
f = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if str1[i - 1] == str2[j - 1]:
f[i][j] = f[i - 1][j - 1] + 1
else:
f[i][j] = max(f[i - 1][j], f[i][j - 1])
ans = []
i, j = m, n
while i or j:
if i == 0:
j -= 1
ans.append(str2[j])
elif j == 0:
i -= 1
ans.append(str1[i])
else:
if f[i][j] == f[i - 1][j]:
i -= 1
ans.append(str1[i])
elif f[i][j] == f[i][j - 1]:
j -= 1
ans.append(str2[j])
else:
i, j = i - 1, j - 1
ans.append(str1[i])
return ''.join(ans[::-1])
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | complexity is O(n * m) due to filling the LCS dp table for all pairs of indices. Space complexity is also O(n * m) for storing the dp table. Optimizations like using two rows instead of full dp can reduce space to O(min(n, m)). |
| 空间 | O(n \cdot m) |
面试官常问的追问
外企场景- question_mark
Candidate recognizes dynamic programming structure for subsequences.
- question_mark
Candidate efficiently computes LCS before merging strings.
- question_mark
Candidate handles edge cases where one string is entirely a subsequence of the other.
常见陷阱
外企场景- error
Not using LCS leads to longer than necessary supersequence.
- error
Incorrectly merging characters may violate subsequence property.
- error
Failing to append remaining unmatched characters at the end of reconstruction.
进阶变体
外企场景- arrow_right_alt
Return all possible shortest common supersequences.
- arrow_right_alt
Compute shortest common supersequence for more than two strings.
- arrow_right_alt
Modify problem to find supersequence minimizing a custom cost function.