线性动态规划:最长公共子序列的变种——带字符出现次数限制的最长公共子序列(进阶版:限制某些字符必须连续出现k次)
字数 1377 2025-11-27 06:55:50

线性动态规划:最长公共子序列的变种——带字符出现次数限制的最长公共子序列(进阶版:限制某些字符必须连续出现k次)

题目描述
给定两个字符串 s1s2,以及一个整数 k(k ≥ 1)。要求找到 s1s2 的最长公共子序列(LCS),但附加条件为:在公共子序列中,某些指定字符必须连续出现至少 k 次。例如,若指定字符为 'a' 且 k=3,则公共子序列中每个 'a' 必须连续出现至少 3 次(如 "aaa" 是合法的,但 "aa" 不合法)。你需要设计一个动态规划算法,计算满足此条件的最长公共子序列的长度。

解题过程

  1. 问题分析

    • 基础 LCS 使用二维 DP 表 dp[i][j] 表示 s1[0:i]s2[0:j] 的 LCS 长度。
    • 新增限制:某些字符(如 'a')在公共子序列中必须连续出现至少 k 次。这意味着在匹配字符时,需跟踪当前连续匹配的长度。
    • 需要扩展状态:除了索引 (i, j),还需记录当前正在匹配的字符 ch 和连续长度 cnt
  2. 状态定义
    定义四维 DP 数组:
    dp[i][j][ch][cnt] 表示考虑 s1 的前 i 个字符和 s2 的前 j 个字符时,以字符 ch 结尾且连续出现 cnt 次的公共子序列的最大长度。

    • 其中 ch 的取值范围为字符集(如小写字母),cnt 的范围为 1k
    • 注意:当 cnt < k 时,子序列未满足连续条件;仅当 cnt >= k 时,当前字符段才合法。
  3. 状态转移

    • Case 1: 不匹配当前字符
      跳过 s1[i]s2[j]
      dp[i][j][ch][cnt] = max(dp[i-1][j][ch][cnt], dp[i][j-1][ch][cnt])  
      
    • Case 2: 匹配字符(s1[i] == s2[j])
      设当前字符 c = s1[i]
      • 子case 2.1: 延续之前的连续字符
        若前一个状态也是字符 c 且连续长度为 cnt-1
        dp[i][j][c][cnt] = dp[i-1][j-1][c][cnt-1] + 1   (若 cnt > 1)  
        
      • 子case 2.2: 开始新的连续段
        若前一个状态是其他字符或 cnt=1
        dp[i][j][c][1] = max(dp[i][j][c][1], max_over_all_ch'{dp[i-1][j-1][ch'][cnt']} + 1)  
        
        其中 ch' 可任意,cnt' 需满足 cnt' >= k(因为新段开始时,前一段必须已合法)。
    • 合法性检查:仅当 cnt >= k 时,当前状态才计入最终答案。
  4. 初始化与边界

    • 初始状态:dp[0][j][ch][cnt] = 0dp[i][0][ch][cnt] = 0(空字符串无公共子序列)。
    • 单独处理 cnt=1 的起始情况。
  5. 复杂度优化

    • 直接四维 DP 可能开销大(O(n²·|Σ|·k))。可优化:
      • (ch, cnt) 合并为二维状态,用哈希表或数组压缩。
      • 仅对指定字符(如 'a')跟踪 cnt,其他字符视为普通 LCS。
  6. 示例演示
    s1 = "aabaa", s2 = "aacaaa", k=3,指定字符为 'a'。

    • 合法公共子序列需包含连续至少 3 个 'a',如 "aaa"。
    • 通过 DP 计算,最终找到最长满足条件的子序列为 "aaa"(长度 3)。

总结
本题通过扩展 LCS 的状态维度,加入字符连续出现的计数约束,解决了带限制的公共子序列问题。关键点在于状态转移时区分连续段的延续与新建,并确保只有满足连续条件的段才被采纳。

线性动态规划:最长公共子序列的变种——带字符出现次数限制的最长公共子序列(进阶版:限制某些字符必须连续出现k次) 题目描述 给定两个字符串 s1 和 s2 ,以及一个整数 k (k ≥ 1)。要求找到 s1 和 s2 的最长公共子序列(LCS),但附加条件为:在公共子序列中, 某些指定字符必须连续出现至少 k 次 。例如,若指定字符为 'a' 且 k=3,则公共子序列中每个 'a' 必须连续出现至少 3 次(如 "aaa" 是合法的,但 "aa" 不合法)。你需要设计一个动态规划算法,计算满足此条件的最长公共子序列的长度。 解题过程 问题分析 基础 LCS 使用二维 DP 表 dp[i][j] 表示 s1[0:i] 和 s2[0:j] 的 LCS 长度。 新增限制:某些字符(如 'a')在公共子序列中必须连续出现至少 k 次。这意味着在匹配字符时,需跟踪当前连续匹配的长度。 需要扩展状态:除了索引 (i, j) ,还需记录当前正在匹配的字符 ch 和连续长度 cnt 。 状态定义 定义四维 DP 数组: dp[i][j][ch][cnt] 表示考虑 s1 的前 i 个字符和 s2 的前 j 个字符时,以字符 ch 结尾且连续出现 cnt 次的公共子序列的最大长度。 其中 ch 的取值范围为字符集(如小写字母), cnt 的范围为 1 到 k 。 注意:当 cnt < k 时,子序列未满足连续条件;仅当 cnt >= k 时,当前字符段才合法。 状态转移 Case 1: 不匹配当前字符 跳过 s1[i] 或 s2[j] : Case 2: 匹配字符(s1[ i] == s2[ j]) 设当前字符 c = s1[i] : 子case 2.1: 延续之前的连续字符 若前一个状态也是字符 c 且连续长度为 cnt-1 : 子case 2.2: 开始新的连续段 若前一个状态是其他字符或 cnt=1 : 其中 ch' 可任意, cnt' 需满足 cnt' >= k (因为新段开始时,前一段必须已合法)。 合法性检查 :仅当 cnt >= k 时,当前状态才计入最终答案。 初始化与边界 初始状态: dp[0][j][ch][cnt] = 0 和 dp[i][0][ch][cnt] = 0 (空字符串无公共子序列)。 单独处理 cnt=1 的起始情况。 复杂度优化 直接四维 DP 可能开销大(O(n²·|Σ|·k))。可优化: 将 (ch, cnt) 合并为二维状态,用哈希表或数组压缩。 仅对指定字符(如 'a')跟踪 cnt ,其他字符视为普通 LCS。 示例演示 设 s1 = "aabaa" , s2 = "aacaaa" , k=3 ,指定字符为 'a'。 合法公共子序列需包含连续至少 3 个 'a',如 "aaa"。 通过 DP 计算,最终找到最长满足条件的子序列为 "aaa"(长度 3)。 总结 本题通过扩展 LCS 的状态维度,加入字符连续出现的计数约束,解决了带限制的公共子序列问题。关键点在于状态转移时区分连续段的延续与新建,并确保只有满足连续条件的段才被采纳。