最长公共子序列的变种:带字符权重的最长公共子序列(进阶版:允许负权重且要求子序列权重和非负,同时限制某些字符必须连续出现k次)
字数 2093 2025-11-12 10:03:26

最长公共子序列的变种:带字符权重的最长公共子序列(进阶版:允许负权重且要求子序列权重和非负,同时限制某些字符必须连续出现k次)

题目描述

给定两个字符串 st,以及一个字符权重数组 weightweight[c] 表示字符 c 的权重,可能为负数),要求找到一个 st 的公共子序列,使得该子序列的权重和最大,并且权重和非负。此外,子序列中某些指定字符(例如 'a')必须连续出现至少 k 次。求满足条件的最大权重和,如果不存在这样的子序列,返回 0。

解题思路

这个问题是经典最长公共子序列(LCS)的变种,增加了权重、非负和以及连续字符出现次数的限制。我们需要设计一个动态规划状态来同时跟踪匹配情况、权重和以及连续字符的出现次数。

详细步骤

步骤1:定义状态

我们定义 dp[i][j][w][cnt] 表示考虑字符串 s 的前 i 个字符和 t 的前 j 个字符时,当前权重和为 w,并且最后一个字符(如果存在)已经连续出现了 cnt 次的情况下,是否能够形成这样的子序列。但直接这样定义状态空间可能太大,我们需要优化。

实际上,我们可以将状态定义为:

  • dp[i][j] 表示考虑 s 的前 i 个字符和 t 的前 j 个字符时,能够得到的最大权重和(且权重和非负)。
  • 同时,我们需要额外的状态来跟踪连续字符的出现次数。我们可以引入一个辅助状态 cont[i][j][ch][k] 表示以字符 ch 结尾且连续出现 k 次的情况,但这样状态空间仍然很大。

为了简化,我们可以将问题分解:

  1. 先忽略连续字符的限制,解决带权重且权重和非负的LCS问题。
  2. 然后加入连续字符的限制。

步骤2:基础动态规划(忽略连续字符限制)

定义 dp[i][j] 为考虑 s 的前 i 个字符和 t 的前 j 个字符时,能得到的最大权重和(且非负)。状态转移方程如下:

  • 如果 s[i-1] == t[j-1],则我们可以选择匹配这个字符:
    dp[i][j] = max(dp[i][j], dp[i-1][j-1] + weight[s[i-1]])
  • 否则,我们可以跳过 s 的当前字符或 t 的当前字符:
    dp[i][j] = max(dp[i][j], dp[i-1][j], dp[i][j-1])

同时,我们需要确保权重和非负,所以如果 dp[i][j] 小于0,我们将其置为0(表示不选择任何字符)。

步骤3:加入连续字符限制

对于连续字符的限制,我们需要额外记录以某个字符结尾的连续出现次数。我们可以定义 cont[i][j][ch] 表示以字符 ch 结尾,在 s 的前 i 个字符和 t 的前 j 个字符中,连续出现的最大次数。

但这样状态空间仍然较大。另一种思路是:我们可以在动态规划过程中,当遇到指定字符(如 'a')时,检查是否已经连续出现了 k 次。如果是,则允许将其加入子序列;否则,不能以该字符作为连续序列的结尾。

我们可以修改状态为:

  • dp[i][j][cnt] 表示考虑 s 的前 i 个字符和 t 的前 j 个字符,且当前指定字符(如 'a')已经连续出现了 cnt 次时的最大权重和。

状态转移:

  1. 如果 s[i-1] == t[j-1]
    • 如果当前字符是指定字符(如 'a'):
      • 如果 cnt > 0,则我们可以继续连续序列:
        dp[i][j][cnt] = max(dp[i][j][cnt], dp[i-1][j-1][cnt-1] + weight['a'])
      • 如果 cnt == 0,则不能以该字符作为连续序列的结尾(因为要求至少连续出现k次)。
    • 如果当前字符不是指定字符:
      • 我们可以匹配该字符,并重置连续计数为0(因为指定字符的连续序列被中断):
        dp[i][j][0] = max(dp[i][j][0], dp[i-1][j-1][cnt] + weight[s[i-1]])
  2. 否则,我们跳过 s[i-1]t[j-1]
    dp[i][j][cnt] = max(dp[i][j][cnt], dp[i-1][j][cnt], dp[i][j-1][cnt])

同时,我们需要确保权重和非负,所以如果任何状态值小于0,我们将其置为0。

步骤4:初始化

  • dp[0][0][0] = 0,表示两个空字符串的权重和为0。
  • 其他状态初始化为0。

步骤5:最终答案

最终答案是所有 dp[len(s)][len(t)][cnt] 中的最大值,其中 cnt >= k(满足连续出现至少k次的条件)。

总结

这个问题的难点在于同时处理权重、非负和以及连续字符出现次数的限制。通过扩展动态规划状态,我们能够跟踪这些信息,并在状态转移时确保所有条件得到满足。虽然状态空间较大,但通过合理的状态设计,我们可以在多项式时间内解决问题。

最长公共子序列的变种:带字符权重的最长公共子序列(进阶版:允许负权重且要求子序列权重和非负,同时限制某些字符必须连续出现k次) 题目描述 给定两个字符串 s 和 t ,以及一个字符权重数组 weight ( weight[c] 表示字符 c 的权重,可能为负数),要求找到一个 s 和 t 的公共子序列,使得该子序列的权重和最大,并且权重和非负。此外,子序列中某些指定字符(例如 'a' )必须连续出现至少 k 次。求满足条件的最大权重和,如果不存在这样的子序列,返回 0。 解题思路 这个问题是经典最长公共子序列(LCS)的变种,增加了权重、非负和以及连续字符出现次数的限制。我们需要设计一个动态规划状态来同时跟踪匹配情况、权重和以及连续字符的出现次数。 详细步骤 步骤1:定义状态 我们定义 dp[i][j][w][cnt] 表示考虑字符串 s 的前 i 个字符和 t 的前 j 个字符时,当前权重和为 w ,并且最后一个字符(如果存在)已经连续出现了 cnt 次的情况下,是否能够形成这样的子序列。但直接这样定义状态空间可能太大,我们需要优化。 实际上,我们可以将状态定义为: dp[i][j] 表示考虑 s 的前 i 个字符和 t 的前 j 个字符时,能够得到的最大权重和(且权重和非负)。 同时,我们需要额外的状态来跟踪连续字符的出现次数。我们可以引入一个辅助状态 cont[i][j][ch][k] 表示以字符 ch 结尾且连续出现 k 次的情况,但这样状态空间仍然很大。 为了简化,我们可以将问题分解: 先忽略连续字符的限制,解决带权重且权重和非负的LCS问题。 然后加入连续字符的限制。 步骤2:基础动态规划(忽略连续字符限制) 定义 dp[i][j] 为考虑 s 的前 i 个字符和 t 的前 j 个字符时,能得到的最大权重和(且非负)。状态转移方程如下: 如果 s[i-1] == t[j-1] ,则我们可以选择匹配这个字符: dp[i][j] = max(dp[i][j], dp[i-1][j-1] + weight[s[i-1]]) 否则,我们可以跳过 s 的当前字符或 t 的当前字符: dp[i][j] = max(dp[i][j], dp[i-1][j], dp[i][j-1]) 同时,我们需要确保权重和非负,所以如果 dp[i][j] 小于0,我们将其置为0(表示不选择任何字符)。 步骤3:加入连续字符限制 对于连续字符的限制,我们需要额外记录以某个字符结尾的连续出现次数。我们可以定义 cont[i][j][ch] 表示以字符 ch 结尾,在 s 的前 i 个字符和 t 的前 j 个字符中,连续出现的最大次数。 但这样状态空间仍然较大。另一种思路是:我们可以在动态规划过程中,当遇到指定字符(如 'a' )时,检查是否已经连续出现了 k 次。如果是,则允许将其加入子序列;否则,不能以该字符作为连续序列的结尾。 我们可以修改状态为: dp[i][j][cnt] 表示考虑 s 的前 i 个字符和 t 的前 j 个字符,且当前指定字符(如 'a' )已经连续出现了 cnt 次时的最大权重和。 状态转移: 如果 s[i-1] == t[j-1] : 如果当前字符是指定字符(如 'a' ): 如果 cnt > 0 ,则我们可以继续连续序列: dp[i][j][cnt] = max(dp[i][j][cnt], dp[i-1][j-1][cnt-1] + weight['a']) 如果 cnt == 0 ,则不能以该字符作为连续序列的结尾(因为要求至少连续出现k次)。 如果当前字符不是指定字符: 我们可以匹配该字符,并重置连续计数为0(因为指定字符的连续序列被中断): dp[i][j][0] = max(dp[i][j][0], dp[i-1][j-1][cnt] + weight[s[i-1]]) 否则,我们跳过 s[i-1] 或 t[j-1] : dp[i][j][cnt] = max(dp[i][j][cnt], dp[i-1][j][cnt], dp[i][j-1][cnt]) 同时,我们需要确保权重和非负,所以如果任何状态值小于0,我们将其置为0。 步骤4:初始化 dp[0][0][0] = 0 ,表示两个空字符串的权重和为0。 其他状态初始化为0。 步骤5:最终答案 最终答案是所有 dp[len(s)][len(t)][cnt] 中的最大值,其中 cnt >= k (满足连续出现至少k次的条件)。 总结 这个问题的难点在于同时处理权重、非负和以及连续字符出现次数的限制。通过扩展动态规划状态,我们能够跟踪这些信息,并在状态转移时确保所有条件得到满足。虽然状态空间较大,但通过合理的状态设计,我们可以在多项式时间内解决问题。