区间动态规划例题:最长公共子序列问题(带权重版本)
字数 2003 2025-11-10 05:32:54
区间动态规划例题:最长公共子序列问题(带权重版本)
题目描述
给定两个字符串 s1 和 s2,以及一个字符权重表 weight(每个字符对应一个整数权重)。要求找到 s1 和 s2 的最长公共子序列(LCS),但不是简单地计算长度,而是计算所有公共子序列中权重和最大的那个子序列的权重和。
例如:
s1 = "abc",s2 = "ac",weight = {'a': 1, 'b': 2, 'c': 3}
公共子序列有"a"(权重1)、"c"(权重3)、"ac"(权重1+3=4)。
最大权重和为4(对应子序列"ac")。
解题过程
-
问题分析
- 经典LCS问题是求最长公共子序列的长度,本题变体为带权重的最大权重公共子序列。
- 若两个字符匹配,不仅增加长度1,还增加该字符的权重。
- 目标:在
s1[0..m-1]和s2[0..n-1]上,找到权重和最大的公共子序列。
-
状态定义
- 定义
dp[i][j]表示s1的前i个字符(即s1[0:i])与s2的前j个字符(即s2[0:j])的最大权重公共子序列的权重和。 - 注意:
i和j分别表示前缀长度(从0开始),当i=0或j=0时,表示空子序列,权重和为0。
- 定义
-
状态转移方程
- Case 1:
s1[i-1] == s2[j-1](当前字符匹配)
匹配的字符c = s1[i-1]权重为w = weight[c]。
我们可以选择将c纳入公共子序列,则权重增加w,并加上前驱状态dp[i-1][j-1]:
dp[i][j] = dp[i-1][j-1] + w - Case 2:
s1[i-1] != s2[j-1](当前字符不匹配)
最大权重公共子序列不可能同时包含s1[i-1]和s2[j-1],但可能:- 排除
s1[i-1],考虑s1[0:i-1]和s2[0:j]:dp[i-1][j] - 排除
s2[j-1],考虑s1[0:i]和s2[0:j-1]:dp[i][j-1]
取最大值:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
- 排除
- Case 1:
-
初始化
dp[0][j] = 0(对任意j,空字符串与s2前缀的公共子序列权重和为0)dp[i][0] = 0(对任意i,s1前缀与空字符串的公共子序列权重和为0)
-
计算顺序
- 按
i从 0 到m,j从 0 到n的顺序填表(m = len(s1),n = len(s2))。 - 最终答案在
dp[m][n]。
- 按
-
示例演算
s1 = "abc",s2 = "ac",weight = {'a':1, 'b':2, 'c':3}- 建表
dp[4][3](因m=3,n=2,但维度为(m+1) x (n+1))
i\j 0 1 (a) 2 (c) 0 0 0 0 1 (a) 0 1 1 2 (b) 0 1 1 3 (c) 0 1 4 - 计算过程:
i=1, j=1:s1[0]='a'匹配s2[0]='a'→dp[1][1] = dp[0][0] + 1 = 1i=1, j=2:'a' != 'c'→max(dp[0][2]=0, dp[1][1]=1) = 1i=2, j=1:'b' != 'a'→max(dp[1][1]=1, dp[2][0]=0) = 1i=2, j=2:'b' != 'c'→max(dp[1][2]=1, dp[2][1]=1) = 1i=3, j=1:'c' != 'a'→max(dp[2][1]=1, dp[3][0]=0) = 1i=3, j=2:'c' == 'c'→dp[3][2] = dp[2][1] + 3 = 1 + 3 = 4
- 结果:
dp[3][2] = 4,符合预期。
-
复杂度分析
- 时间复杂度:O(mn),需要填充 m×n 的DP表。
- 空间复杂度:O(mn),可优化至 O(min(m,n))(只保留当前行和上一行)。
关键点
- 本题在经典LCS的“长度”基础上,将“+1”改为“+weight[c]”,其余逻辑一致。
- 若权重全为1,则退化为经典LCS长度问题。