线性动态规划:最长公共子序列的变种——带字符权重的最长公共子序列(进阶版:允许负权重且要求子序列权重和非负,同时限制某些字符必须连续出现)
字数 1394 2025-11-08 20:56:04
线性动态规划:最长公共子序列的变种——带字符权重的最长公共子序列(进阶版:允许负权重且要求子序列权重和非负,同时限制某些字符必须连续出现)
题目描述
给定两个字符串 s1 和 s2,每个字符有一个权重(可能为负数),要求找到它们的公共子序列,满足:
- 子序列的权重和(即字符权重之和)非负;
- 子序列中必须连续出现某个特定子串
pattern(即pattern必须是子序列的连续部分); - 允许字符权重为负,但最终权重和需非负。
求满足条件的最长公共子序列的长度及其最大权重和(若权重和相同,取长度更长的子序列)。
解题思路
此题结合了最长公共子序列(LCS)、权重约束、连续子串限制三个难点。我们需要在动态规划状态中记录:
- 当前匹配到的
s1和s2的位置; - 当前已匹配的
pattern的长度(用于保证连续出现); - 当前权重和(需保证非负)。
步骤详解
-
状态定义
定义dp[i][j][k][w]表示考虑s1的前i个字符和s2的前j个字符时,已匹配pattern的前k个字符,且当前权重和为w时的最长公共子序列长度。i范围:0 到len(s1);j范围:0 到len(s2);k范围:0 到len(pattern)(k=len(pattern)表示已完整匹配pattern);w范围:权重和可能为负,但需限制范围(可通过偏移量处理)。
-
权重偏移处理
由于权重可能为负,我们将所有权重加上一个足够大的常数BASE,使得权重和始终非负,但需注意BASE的选择不影响最终结果(因为只关心相对值)。 -
状态转移
- 若
s1[i-1] == s2[j-1]:
当前字符可加入子序列。- 更新权重
nw = w + weight[s1[i-1]]。 - 对于
pattern的匹配状态k:- 如果
k < len(pattern)且s1[i-1] == pattern[k],则k可推进至k+1; - 否则
k保持不变(但需保证k不倒退)。
- 如果
- 转移方程:
dp[i][j][nk][nw] = max(dp[i][j][nk][nw], dp[i-1][j-1][k][w] + 1)
其中nk为更新后的pattern匹配长度。
- 更新权重
- 若字符不相等:
继承dp[i-1][j][k][w]或dp[i][j-1][k][w]的状态。
- 若
-
初始化和边界
dp[0][0][0][BASE] = 0(空序列,权重和为 0,偏移后为BASE)。- 其他状态初始化为负无穷(表示不可达)。
-
结果提取
遍历所有i,j,且k = len(pattern)(保证pattern完整匹配),w >= BASE(权重和非负),取最大的dp[i][j][k][w]。
关键点
- 通过四维状态同时处理 LCS、连续子串匹配、权重约束;
- 权重偏移避免负索引;
- 完整匹配
pattern后才更新最终结果。
此解法时间复杂度为 O(n²·m·W),其中 n 为字符串长度,m 为 pattern 长度,W 为权重范围,适用于小规模问题。