最长公共子序列的变种:带字符替换限制的最长公共子序列(进阶版:允许部分字符替换为通配符)
字数 1093 2025-11-05 23:45:49

最长公共子序列的变种:带字符替换限制的最长公共子序列(进阶版:允许部分字符替换为通配符)

题目描述
给定两个字符串 s1s2,以及一个字符替换规则:允许将 s1 中的某些特定字符(称为“可替换字符”)替换为通配符 *,该通配符可以匹配 s2 中的任意字符(包括连续多个字符)。此外,通配符在 s1 中最多连续出现次数有限制(设为 k,即通配符段长度不超过 k)。求在这种替换规则下,s1s2 的最长公共子序列(LCS)长度。

解题过程

  1. 问题分析

    • 常规 LCS 问题中,字符必须精确匹配。
    • 本题允许将 s1 的部分字符替换为通配符,通配符可匹配 s2 的任意字符,但通配符段长度受限。
    • 目标:利用替换规则最大化 LCS 长度。
  2. 状态定义
    dp[i][j] 表示考虑 s1 的前 i 个字符和 s2 的前 j 个字符时,能得到的最大 LCS 长度。
    额外状态 cnt[i][j] 表示在 dp[i][j] 状态下,当前连续通配符段的长度(若末尾非通配符则为 0)。

  3. 状态转移

    • 情况1:精确匹配
      s1[i-1] == s2[j-1],则直接继承 dp[i-1][j-1] + 1,且重置通配符计数:
      dp[i][j] = max(dp[i][j], dp[i-1][j-1] + 1)
      cnt[i][j] = 0  // 匹配后通配符段中断
      
    • 情况2:使用通配符替换
      s1[i-1] 是可替换字符,且当前通配符段长度 < k,则可将 s1[i-1] 替换为通配符,匹配 s2[j-1]
      dp[i][j] = max(dp[i][j], dp[i-1][j-1] + 1)  // 通配符匹配一个字符
      cnt[i][j] = cnt[i-1][j-1] + 1  // 通配符段延长
      
      同时,通配符可匹配 s2 的多个字符,需检查 s1 前导通配符段:
      for t in [1, min(k, i)]:  // 尝试用长度为t的通配符段匹配s2的末尾字符
          if cnt[i-t][j-1] == t:  // 前t个字符是通配符段
              dp[i][j] = max(dp[i][j], dp[i-t][j-1] + 1)
              cnt[i][j] = t  // 延续通配符段
      
    • 情况3:跳过字符
      跳过 s1[i-1]s2[j-1]
      dp[i][j] = max(dp[i-1][j], dp[i][j-1])
      // 通配符段继承或重置(根据具体选择)
      
  4. 初始化

    • dp[0][j] = 0, dp[i][0] = 0(空字符串无公共子序列)。
    • cnt[0][j] = 0, cnt[i][0] = 0
  5. 复杂度优化

    • 直接实现复杂度为 O(n³),可通过预处理前导通配符段长度优化到 O(n²)。
  6. 示例演示
    s1 = "aXb", s2 = "acb", 可替换字符集 {X}, k=1

    • 步骤1:精确匹配 adp[1][1]=1
    • 步骤2:s1[1]='X' 可替换,用通配符匹配 s2[1]='c'dp[2][2]=2
    • 步骤3:精确匹配 bdp[3][3]=3
    • 结果:LCS 长度为 3(通配符帮助匹配了 c)。

关键点

  • 通配符的连续使用受长度限制,需通过 cnt 状态跟踪。
  • 通配符可匹配任意字符,但需在状态转移中合理处理多字符匹配情况。
最长公共子序列的变种:带字符替换限制的最长公共子序列(进阶版:允许部分字符替换为通配符) 题目描述 给定两个字符串 s1 和 s2 ,以及一个字符替换规则:允许将 s1 中的某些特定字符(称为“可替换字符”)替换为通配符 * ,该通配符可以匹配 s2 中的任意字符(包括连续多个字符)。此外,通配符在 s1 中最多连续出现次数有限制(设为 k ,即通配符段长度不超过 k )。求在这种替换规则下, s1 和 s2 的最长公共子序列(LCS)长度。 解题过程 问题分析 常规 LCS 问题中,字符必须精确匹配。 本题允许将 s1 的部分字符替换为通配符,通配符可匹配 s2 的任意字符,但通配符段长度受限。 目标:利用替换规则最大化 LCS 长度。 状态定义 设 dp[i][j] 表示考虑 s1 的前 i 个字符和 s2 的前 j 个字符时,能得到的最大 LCS 长度。 额外状态 cnt[i][j] 表示在 dp[i][j] 状态下,当前连续通配符段的长度(若末尾非通配符则为 0)。 状态转移 情况1:精确匹配 若 s1[i-1] == s2[j-1] ,则直接继承 dp[i-1][j-1] + 1 ,且重置通配符计数: 情况2:使用通配符替换 若 s1[i-1] 是可替换字符,且当前通配符段长度 < k ,则可将 s1[i-1] 替换为通配符,匹配 s2[j-1] : 同时,通配符可匹配 s2 的多个字符,需检查 s1 前导通配符段: 情况3:跳过字符 跳过 s1[i-1] 或 s2[j-1] : 初始化 dp[0][j] = 0 , dp[i][0] = 0 (空字符串无公共子序列)。 cnt[0][j] = 0 , cnt[i][0] = 0 。 复杂度优化 直接实现复杂度为 O(n³),可通过预处理前导通配符段长度优化到 O(n²)。 示例演示 设 s1 = "aXb" , s2 = "acb" , 可替换字符集 {X} , k=1 。 步骤1:精确匹配 a , dp[1][1]=1 。 步骤2: s1[1]='X' 可替换,用通配符匹配 s2[1]='c' , dp[2][2]=2 。 步骤3:精确匹配 b , dp[3][3]=3 。 结果:LCS 长度为 3(通配符帮助匹配了 c )。 关键点 通配符的连续使用受长度限制,需通过 cnt 状态跟踪。 通配符可匹配任意字符,但需在状态转移中合理处理多字符匹配情况。