最长公共子序列的变种:带字符权重的最长公共子序列(进阶版:允许负权重且要求子序列权重和非负,同时限制某些字符必须连续出现)
字数 929 2025-11-07 22:14:45
最长公共子序列的变种:带字符权重的最长公共子序列(进阶版:允许负权重且要求子序列权重和非负,同时限制某些字符必须连续出现)
题目描述:给定两个字符串s和t,每个字符有一个权重(可能为负数)。要求找到s和t的一个公共子序列,使得该子序列的权重和最大(非负),并且满足以下条件:子序列中某些特定字符(给定集合)必须连续出现(即如果该字符出现在子序列中,那么它必须连续出现至少k次,k为给定值)。
解题过程:
-
问题分析:
- 这是LCS的增强版,增加了三个约束:字符权重(可负)、权重和非负、特定字符必须连续出现
- 需要同时考虑子序列的匹配、权重累计和连续性约束
-
状态定义:
- dp[i][j][w]表示考虑s的前i个字符和t的前j个字符,当前权重和为w时的最长匹配长度
- 但由于权重范围可能很大,我们改为:dp[i][j]表示以s[i]和t[j]结尾的最大权重公共子序列
- 增加状态cnt[c]记录当前字符c的连续出现次数
-
状态转移方程:
- 基础情况:dp[0][j] = dp[i][0] = 0
- 当s[i] == t[j]时:
- 如果s[i]是必须连续出现的字符:
- 如果前一个字符也是s[i]:dp[i][j] = max(dp[i][j], dp[i-1][j-1] + weight[s[i]])
- 否则需要检查是否满足最小连续次数要求
- 否则:dp[i][j] = max(dp[i][j], dp[i-1][j-1] + weight[s[i]])
- 如果s[i]是必须连续出现的字符:
- 不考虑当前匹配:dp[i][j] = max(dp[i-1][j], dp[i][j-1])
-
连续性约束处理:
- 对于必须连续出现的字符,维护连续计数器
- 当字符变化时,检查前一个字符序列是否满足最小长度要求
- 如果不满足,需要回退到上一个有效状态
-
权重非负约束:
- 在状态转移过程中,如果权重和变为负数,则放弃当前路径
- 只记录权重非负的状态
-
算法优化:
- 使用滚动数组优化空间复杂度
- 预处理必须连续出现的字符集合
- 对于权重计算,使用前缀和优化
这个问题的难点在于同时处理多种约束条件,需要仔细设计状态转移方程来确保所有约束都被满足。