线性动态规划:最长公共子序列的变种——带字符插入/删除/替换代价的最短编辑距离(Edit Distance with Custom Costs)
字数 1350 2025-11-27 02:24:32
线性动态规划:最长公共子序列的变种——带字符插入/删除/替换代价的最短编辑距离(Edit Distance with Custom Costs)
题目描述
给定两个字符串 s1 和 s2,以及三个操作(插入、删除、替换)的代价。每次操作可以将一个字符插入 s1、从 s1 删除一个字符,或将 s1 的一个字符替换为另一个字符。目标是通过一系列操作将 s1 转换为 s2,并使得总操作代价最小。要求设计动态规划算法求解最小总代价。
解题过程
-
定义状态
设dp[i][j]表示将s1的前i个字符转换为s2的前j个字符所需的最小代价。i的取值范围:0 ≤ i ≤ len(s1)j的取值范围:0 ≤ j ≤ len(s2)
-
初始化边界情况
- 当
i = 0时,s1为空,只能通过插入j个字符得到s2的前j个字符:
dp[0][j] = j * cost_insert(cost_insert为插入一个字符的代价) - 当
j = 0时,s2为空,只能通过删除i个字符将s1变为空字符串:
dp[i][0] = i * cost_delete(cost_delete为删除一个字符的代价)
- 当
-
状态转移方程
对于一般情况i > 0且j > 0,考虑对s1的第i个字符(即s1[i-1])的三种操作:- 删除:删除
s1[i-1],问题转化为将s1的前i-1个字符转换为s2的前j个字符,代价为:
dp[i-1][j] + cost_delete - 插入:在
s1的第i个位置后插入s2[j-1],问题转化为将s1的前i个字符转换为s2的前j-1个字符,代价为:
dp[i][j-1] + cost_insert - 替换:
- 若
s1[i-1] == s2[j-1],无需替换,直接继承子问题代价:dp[i-1][j-1] - 否则,将
s1[i-1]替换为s2[j-1],代价为:dp[i-1][j-1] + cost_replace(cost_replace为替换代价)
- 若
综合上述情况,状态转移方程为:
dp[i][j] = min( dp[i-1][j] + cost_delete, # 删除 dp[i][j-1] + cost_insert, # 插入 dp[i-1][j-1] + (0 if s1[i-1] == s2[j-1] else cost_replace) # 替换或匹配 ) - 删除:删除
-
计算顺序与最终答案
- 按
i从0到len(s1),j从0到len(s2)的顺序填充dp表。 - 最终答案为
dp[len(s1)][len(s2)],即整个字符串转换的最小代价。
- 按
示例
设 s1 = "horse", s2 = "ros",操作代价均为 1(标准编辑距离):
- 计算
dp表后得到最小代价为3(删除h、替换r为o、删除e)。
若替换代价为2,则最小代价为4(通过删除和插入操作避免高代价替换)。
关键点
- 通过自定义代价,可灵活处理不同场景(如替换代价较高时倾向于插入/删除)。
- 时间复杂度
O(mn),空间复杂度可通过滚动数组优化至O(min(m, n))。