线性动态规划:最长公共子序列的变种——带字符出现次数限制的最长公共子序列(进阶版:限制某些字符必须连续出现)
题目描述
给定两个字符串 s1 和 s2,以及一个限制条件:在最长公共子序列(LCS)中,某些特定字符(例如字符 'a')必须连续出现至少 k 次(k ≥ 1)。要求找到满足该限制条件的最长公共子序列的长度。如果不存在这样的子序列,返回 0。
示例
输入:
s1 = "aabcde"
s2 = "acabde"
限制字符:'a',连续出现至少 k = 2 次
输出:4
解释:满足条件的 LCS 为 "aabd"(其中 'a' 未连续出现 2 次)或 "abde"(同样不满足),但实际正确答案是 "aabde" 吗?注意:"aabde" 不是公共子序列。实际上,满足条件的 LCS 是 "aab"?不,正确解是:公共子序列 "aabd" 中 'a' 连续出现 1 次,不符合;"abde" 中无连续 'a';但存在 "aab"?检查:s1 和 s2 的公共子序列 "aab" 中 'a' 连续出现 2 次(即 "aa"),且长度为 3。但更长的 "aabde" 不存在。实际上,最长满足条件的子序列是 "aab",长度为 3?但示例输出为 4,说明可能为 "aabd"?这里需要重新审题:限制是“必须包含连续出现至少 k 次的特定字符”,而不是“整个子序列中该字符必须连续出现”。因此,子序列中只需存在一个连续段(长度 ≥ k)即可。例如,"aabde" 不是公共子序列,但 "aabd" 是(s1: aab_c_d, s2: a_cab_d),其中 'a' 连续出现 2 次,长度为 4。
解题过程
-
问题分析
- 基础 LCS 使用动态规划:
dp[i][j]表示s1[0..i-1]和s2[0..j-1]的 LCS 长度。 - 新增限制:子序列中必须包含一段连续至少
k个特定字符(如'a')。 - 思路:扩展状态,记录当前末尾连续特定字符的长度。
- 基础 LCS 使用动态规划:
-
状态定义
定义dp[i][j][c]:考虑s1[0..i-1]和s2[0..j-1],且公共子序列末尾连续字符'a'的长度为c时的最大长度。c的范围:0 ≤ c ≤ k(当c == k时,表示已满足连续至少k次的条件)。- 为简化,可将
c分为两类:未满足条件(c < k)和已满足条件(c ≥ k)。但只需记录c直到k(因为c ≥ k时效果相同)。
-
状态转移
- 初始化:
dp[0][j][0] = 0,dp[i][0][0] = 0,其余为负无穷(表示不可达)。 - 转移方程:
a. 不选当前字符:继承dp[i-1][j][c]或dp[i][j-1][c]。
b. 选当前字符(仅当s1[i-1] == s2[j-1]):- 若当前字符是限制字符(如
'a'):
dp[i][j][c] = max(dp[i][j][c], dp[i-1][j-1][c-1] + 1),其中c ≥ 1。
特殊地,若c = 1,则前状态c' = 0。 - 若当前字符不是限制字符:
选择后,连续计数c重置为 0:
dp[i][j][0] = max(dp[i][j][0], dp[i-1][j-1][c'] + 1),其中c'为任意值。
c. 已满足条件的状态:一旦c == k,后续可保持已满足状态(即使连续中断,因为条件已满足)。
- 若当前字符是限制字符(如
- 初始化:
-
优化状态设计
实际可定义两个状态数组:dp0[i][j]:未满足连续条件时的最大长度。dp1[i][j]:已满足条件时的最大长度。
转移时:- 当字符匹配:
- 若是
'a':- 从
dp0[i-1][j-1]转移来,且之前连续'a'计数为t,需额外维护计数?但这样仍需记录计数。
- 从
- 若是
- 因此,仍需显式记录
c,但可将c维度上限设为k。
-
具体转移方程
设dp[i][j][c]表示以s1[i-1]和s2[j-1]结尾的公共子序列的连续'a'长度为c时的最大长度。
转移:- 不选
s1[i-1]:dp[i][j][c] = max(dp[i][j][c], dp[i-1][j][c]) - 不选
s2[j-1]:dp[i][j][c] = max(dp[i][j][c], dp[i][j-1][c]) - 选两者(当
s1[i-1] == s2[j-1]):
令x = s1[i-1]- 若
x == 'a':- 若
c > 0:dp[i][j][c] = max(dp[i][j][c], dp[i-1][j-1][c-1] + 1) - 若
c == 0:不可由前面转移(因为当前是'a',连续计数至少为 1)
- 若
- 若
x != 'a':- 只有
c == 0时:dp[i][j][0] = max(dp[i][j][0], dp[i-1][j-1][c'] + 1),其中c'任意(因为非'a'会中断连续,但条件可能已满足)。 - 若
c > 0,则不能以非'a'结尾却保持连续'a'计数。
- 只有
- 若
- 不选
-
最终答案
max{ dp[n][m][c] },其中c == k或c ≥ k(若定义c上限为k,则取c = k)。
示例计算
以 s1="aabcde", s2="acabde", k=2 为例,部分计算过程:
- 匹配
'a'时,连续计数增加。 - 匹配到第二个
'a'时,连续计数达到 2,满足条件。 - 最终得到最长满足条件的子序列为
"aab"或更长?验证可得最终长度为 4(对应"aabd")。
通过以上步骤,可解决带字符连续出现次数限制的 LCS 问题。