最长公共子序列的变种:带字符替换限制的最长公共子序列(进阶版:允许部分字符替换为通配符)
字数 1068 2025-11-02 19:16:02

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

题目描述
给定两个字符串s和t,以及一个字符替换规则:某些特定字符可以被替换为通配符'?'(通配符可以匹配任意字符)。求在允许进行字符替换操作后,s和t的最长公共子序列(LCS)长度。注意:每个字符最多只能被替换一次,且只能替换为通配符。

解题过程

步骤1:问题分析
这是标准LCS问题的变种,关键区别在于允许将特定字符替换为通配符。通配符可以匹配任意字符,这增加了匹配的灵活性。我们需要在动态规划状态中记录替换操作的使用情况。

步骤2:状态定义
定义三维DP数组:

  • dp[i][j][k] 表示考虑字符串s的前i个字符和t的前j个字符,在使用k次替换操作的情况下,能得到的最长公共子序列长度。
  • 其中k的取值范围为0到最大允许替换次数(本题中为特定字符的数量)。

步骤3:状态转移方程
考虑字符匹配的几种情况:

  1. 不匹配任何字符
    dp[i][j][k] = max(dp[i-1][j][k], dp[i][j-1][k])

  2. 字符直接匹配(s[i-1] == t[j-1]):
    dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k] + 1)

  3. 使用通配符匹配

    • 如果s[i-1]可以被替换为通配符:
      dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k-1] + 1) (当k > 0时)
    • 如果t[j-1]可以被替换为通配符:
      dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k-1] + 1) (当k > 0时)

步骤4:初始化

  • dp[0][j][k] = 0 (空字符串与任何字符串的LCS为0)
  • dp[i][0][k] = 0
  • dp[0][0][k] = 0

步骤5:算法实现

def lcs_with_replacement(s, t, replaceable_chars):
    m, n = len(s), len(t)
    max_k = sum(1 for c in s if c in replaceable_chars) + \
            sum(1 for c in t if c in replaceable_chars)
    
    dp = [[[0] * (max_k + 1) for _ in range(n + 1)] for _ in range(m + 1)]
    
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            for k in range(max_k + 1):
                # 情况1:不匹配当前字符
                dp[i][j][k] = max(dp[i-1][j][k], dp[i][j-1][k])
                
                # 情况2:直接匹配
                if s[i-1] == t[j-1]:
                    dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k] + 1)
                
                # 情况3:使用通配符匹配
                if k > 0:
                    if s[i-1] in replaceable_chars:
                        dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k-1] + 1)
                    if t[j-1] in replaceable_chars:
                        dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k-1] + 1)
    
    return max(dp[m][n])

步骤6:复杂度分析

  • 时间复杂度:O(m × n × K),其中K为最大替换次数
  • 空间复杂度:O(m × n × K),可通过滚动数组优化到O(n × K)

步骤7:示例验证
设s = "ABC", t = "ADC", 可替换字符集 = {'B', 'D'}

  • 最大替换次数K = 2(s中有1个可替换字符,t中有1个)
  • 最优解:将B替换为通配符,匹配t的D;或者将D替换为通配符,匹配s的B
  • LCS长度 = 2("AC")

这个算法通过三维动态规划有效处理了字符替换的限制条件,扩展了标准LCS的应用范围。

最长公共子序列的变种:带字符替换限制的最长公共子序列(进阶版:允许部分字符替换为通配符) 题目描述 给定两个字符串s和t,以及一个字符替换规则:某些特定字符可以被替换为通配符'?'(通配符可以匹配任意字符)。求在允许进行字符替换操作后,s和t的最长公共子序列(LCS)长度。注意:每个字符最多只能被替换一次,且只能替换为通配符。 解题过程 步骤1:问题分析 这是标准LCS问题的变种,关键区别在于允许将特定字符替换为通配符。通配符可以匹配任意字符,这增加了匹配的灵活性。我们需要在动态规划状态中记录替换操作的使用情况。 步骤2:状态定义 定义三维DP数组: dp[i][j][k] 表示考虑字符串s的前i个字符和t的前j个字符,在使用k次替换操作的情况下,能得到的最长公共子序列长度。 其中k的取值范围为0到最大允许替换次数(本题中为特定字符的数量)。 步骤3:状态转移方程 考虑字符匹配的几种情况: 不匹配任何字符 : dp[i][j][k] = max(dp[i-1][j][k], dp[i][j-1][k]) 字符直接匹配 (s[ i-1] == t[ j-1 ]): dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k] + 1) 使用通配符匹配 : 如果s[ i-1 ]可以被替换为通配符: dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k-1] + 1) (当k > 0时) 如果t[ j-1 ]可以被替换为通配符: dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-1][k-1] + 1) (当k > 0时) 步骤4:初始化 dp[0][j][k] = 0 (空字符串与任何字符串的LCS为0) dp[i][0][k] = 0 dp[0][0][k] = 0 步骤5:算法实现 步骤6:复杂度分析 时间复杂度:O(m × n × K),其中K为最大替换次数 空间复杂度:O(m × n × K),可通过滚动数组优化到O(n × K) 步骤7:示例验证 设s = "ABC", t = "ADC", 可替换字符集 = {'B', 'D'} 最大替换次数K = 2(s中有1个可替换字符,t中有1个) 最优解:将B替换为通配符,匹配t的D;或者将D替换为通配符,匹配s的B LCS长度 = 2("AC") 这个算法通过三维动态规划有效处理了字符替换的限制条件,扩展了标准LCS的应用范围。