最长公共子序列的变种:带字符插入/删除/替换代价的最短公共超序列(Shortest Common Supersequence with Custom Costs)
字数 1576 2025-11-09 07:28:11
最长公共子序列的变种:带字符插入/删除/替换代价的最短公共超序列(Shortest Common Supersequence with Custom Costs)
题目描述
给定两个字符串 s1 和 s2,以及三个操作的成本:插入一个字符的成本 insert_cost、删除一个字符的成本 delete_cost、替换一个字符的成本 replace_cost。目标是找到包含 s1 和 s2 作为子序列的最短字符串(即最短公共超序列),并使得构造该超序列的总操作成本最小。操作允许在任意位置插入、删除或替换字符,且每次操作的成本固定。
解题过程
-
问题分析
- 最短公共超序列(SCS)是包含两个字符串作为子序列的最短字符串。
- 本题中,操作成本可能不对称(例如插入和删除成本不同),需通过动态规划计算最小成本。
- 关键点:超序列的生成可视为对
s1和s2的编辑过程,通过插入、删除、替换操作使两字符串对齐。
-
状态定义
- 定义
dp[i][j]表示将s1的前i个字符和s2的前j个字符转化为超序列的最小成本。 - 初始状态:
dp[0][0] = 0(两个空字符串无需操作)。dp[i][0] = i * delete_cost(删除s1的前i个字符)。dp[0][j] = j * insert_cost(将s2的前j个字符插入到空字符串)。
- 定义
-
状态转移方程
- 对于
s1[i-1]和s2[j-1]:- 若
s1[i-1] == s2[j-1]:直接匹配,无需额外成本,dp[i][j] = dp[i-1][j-1]。 - 若字符不相等,考虑三种操作:
- 删除
s1[i-1]:成本为delete_cost,状态转移为dp[i][j] = dp[i-1][j] + delete_cost。 - 插入
s2[j-1]:成本为insert_cost,状态转移为dp[i][j] = dp[i][j-1] + insert_cost。 - 替换
s1[i-1]为s2[j-1]:成本为replace_cost,状态转移为dp[i][j] = dp[i-1][j-1] + replace_cost。
- 删除
- 若
- 最终
dp[i][j]取上述情况的最小值:dp[i][j] = min( dp[i-1][j] + delete_cost, dp[i][j-1] + insert_cost, dp[i-1][j-1] + (0 if s1[i-1] == s2[j-1] else replace_cost) )
- 对于
-
示例计算
设s1 = "abc",s2 = "adc",成本为insert_cost = 1,delete_cost = 1,replace_cost = 2。- 初始化:
dp[0][0] = 0 dp[1][0] = 1, dp[2][0] = 2, dp[3][0] = 3 dp[0][1] = 1, dp[0][2] = 2, dp[0][3] = 3 - 计算
dp[1][1]:s1[0] = 'a'等于s2[0] = 'a',直接匹配,dp[1][1] = dp[0][0] = 0。 - 计算
dp[1][2]:s1[0] = 'a'不等于s2[1] = 'd',取最小值:- 删除 'a':
dp[0][2] + 1 = 2 + 1 = 3 - 插入 'd':
dp[1][1] + 1 = 0 + 1 = 1 - 替换 'a' 为 'd':
dp[0][1] + 2 = 1 + 2 = 3
最小值为1,故dp[1][2] = 1。
- 删除 'a':
- 最终
dp[3][3] = 2(超序列为"adbc",成本:插入 'd' 成本 1,匹配 'b' 和 'c' 无成本)。
- 初始化:
-
复杂度分析
- 时间复杂度:O(mn),其中 m 和 n 为两字符串长度。
- 空间复杂度:可优化至 O(min(m, n)),通过滚动数组存储状态。
总结
本题通过动态规划将字符匹配问题转化为成本最小化问题,状态转移需综合考虑插入、删除、替换操作的代价差异,最终得到最小成本超序列。