线性动态规划:最长公共子序列的变种——带字符限制的最长公共子序列(进阶版:限制某些字符必须连续出现)
字数 1525 2025-11-01 09:19:03
线性动态规划:最长公共子序列的变种——带字符限制的最长公共子序列(进阶版:限制某些字符必须连续出现)
题目描述
给定两个字符串 s1 和 s2,以及一个限制字符串 pattern。要求找到 s1 和 s2 的最长公共子序列(LCS),且该子序列必须包含 pattern 作为连续子串(即 pattern 的字符必须连续出现,不能间隔)。例如:
s1 = "abcde",s2 = "ace",pattern = "c",满足条件的 LCS 是"ace"(包含连续子串"c")。- 若
pattern = "cd",则需在 LCS 中连续出现"cd",此时无解(因为s2中"c"和e不连续)。
解题思路
-
问题拆分:
- 先找到
s1和s2的普通 LCS。 - 增加约束:LCS 必须连续包含
pattern。 - 可转化为在
s1和s2中匹配pattern,再扩展匹配位置的前后部分。
- 先找到
-
动态规划定义:
定义三维 DP 数组dp[i][j][k]:i:遍历s1的前i个字符。j:遍历s2的前j个字符。k:表示当前已匹配pattern的前k个字符(0 ≤ k ≤ len(pattern))。- 状态值:在
s1[0..i-1]和s2[0..j-1]中,匹配了pattern[0..k-1]时的最长公共子序列长度。
-
状态转移:
- Case 1:
s1[i-1] == s2[j-1]- 若当前字符等于
pattern[k],则k可推进:dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k-1] + 1)(需k>0)。 - 若当前字符不等于
pattern[k],但k == len(pattern)(已完整匹配pattern),则直接扩展 LCS:dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k] + 1)。
- 若当前字符等于
- Case 2:字符不匹配时,继承之前状态:
dp[i][j][k] = max(dp[i-1][j][k], dp[i][j-1][k]) - 特殊处理:当
k == 0(未匹配任何pattern字符)时,仅需计算普通 LCS。
- Case 1:
-
初始化:
dp[0][j][k] = dp[i][0][k] = -∞(无效状态,但k=0时可设为 0)。dp[0][0][0] = 0。
-
答案提取:
- 最终答案为
dp[len(s1)][len(s2)][len(pattern)],若其值小于len(pattern)则无解。
- 最终答案为
示例演示
以 s1 = "abcde", s2 = "ace", pattern = "c" 为例:
- 匹配
pattern="c":- 当
s1[i]='c'且s2[j]='c'时,k从 0 推进到 1。 - 完整匹配后,继续扩展前后字符(如
"a"和"e")。
- 当
- 最终 LCS 为
"ace",包含连续子串"c",长度为 3。
复杂度分析
- 时间复杂度:O(n·m·p),其中
n, m, p分别为s1,s2,pattern的长度。 - 空间复杂度:可优化至 O(m·p) 使用滚动数组。
关键点
- 通过
k维度控制pattern的连续匹配进度,确保最终解包含连续pattern。 - 需区分“正在匹配
pattern”和“已完成匹配”两种状态,后者允许扩展任意字符。