括号匹配的最大得分问题(带权值版本)
字数 1518 2025-11-05 23:45:42

括号匹配的最大得分问题(带权值版本)

题目描述:
给定一个由 '(' 和 ')' 组成的字符串 s,以及一个得分数组 score,其中 score[i] 表示第 i 个字符的权值得分。我们需要找出一个合法的括号子序列(不一定连续),使得这个子序列中所有字符的权值之和最大。合法的括号序列定义为:空串是合法的;如果 A 和 B 是合法的,那么 AB 也是合法的;如果 A 是合法的,那么 (A) 也是合法的。

解题过程:

  1. 定义状态:设 dp[i][j] 表示在子串 s[i:j+1](即从索引 i 到 j 的闭区间)中,能获得的最大得分。注意,这里我们考虑的是不要求连续的子序列。

  2. 状态转移:

    • 情况1:不考虑字符 i。那么最大得分就是 dp[i+1][j]。
    • 情况2:如果 s[i] 是 '(',我们尝试为它匹配一个在位置 k (i < k <= j) 的 ')',使得 s[k] 是 ')'。这样,我们可以将区间分成三部分:
      • 内部区间 [i+1, k-1]:这是一个合法的括号序列,得分是 dp[i+1][k-1]。
      • 匹配的括号对 (i, k):得分是 score[i] + score[k]。
      • 外部区间 [k+1, j]:得分是 dp[k+1][j]。
        总得分是这三部分的和。我们需要遍历所有可能的 k,取最大值。
    • 此外,区间 [i, j] 可能由两个合法的括号序列拼接而成,即存在一个分割点 m (i <= m < j),使得总得分 = dp[i][m] + dp[m+1][j]。我们也需要遍历所有可能的 m,取最大值。
  3. 初始化:对于长度为0的区间(即 i > j),dp[i][j] = 0。对于长度为1的区间,由于单个字符无法形成合法的括号对(除非是空,但空序列得分0),所以 dp[i][i] = 0。

  4. 计算顺序:由于 dp[i][j] 依赖于更短的区间(即区间长度更小),所以我们按区间长度 len 从小到大进行计算,从 len=2 开始(因为至少需要两个字符才能形成一对括号)。

  5. 最终答案:整个字符串 s[0:n-1] 的最大得分就是 dp[0][n-1]。

举例说明:
假设 s = "()()", score = [1, 2, 3, 4]。

  • 区间长度2:
    • [0,1]: s[0]='(', s[1]=')',匹配,得分=1+2=3。dp[0][1]=3。
    • [1,2]: s[1]=')', s[2]='(',无法匹配,dp[1][2]=0。
    • [2,3]: s[2]='(', s[3]=')',匹配,得分=3+4=7。dp[2][3]=7。
  • 区间长度4:[0,3]:
    • 情况1:不考虑s[0],得分=dp[1][3]。需要计算dp[1][3]:区间[1,3]=")(",内部无法形成合法序列,但可以分割为[1,2]和[3,3](但dp[3][3]=0),所以dp[1][3]=0。
    • 情况2:s[0]='(',尝试匹配k=1,3。
      • k=1:内部[1,0]无效(得分0),匹配得分=1+2=3,外部[2,3]得分=7,总=10。
      • k=3:内部[1,2]=")(",dp[1][2]=0,匹配得分=1+4=5,外部无,总=5。
        最大值10。
    • 情况3:分割点m=1:dp[0][1]+dp[2][3]=3+7=10。
      所以dp[0][3]=max(0, 10, 10)=10。

最终最大得分是10,对应的子序列是取整个字符串"()()"。

括号匹配的最大得分问题(带权值版本) 题目描述: 给定一个由 '(' 和 ')' 组成的字符串 s,以及一个得分数组 score,其中 score[ i ] 表示第 i 个字符的权值得分。我们需要找出一个合法的括号子序列(不一定连续),使得这个子序列中所有字符的权值之和最大。合法的括号序列定义为:空串是合法的;如果 A 和 B 是合法的,那么 AB 也是合法的;如果 A 是合法的,那么 (A) 也是合法的。 解题过程: 定义状态:设 dp[ i][ j] 表示在子串 s[ i:j+1 ](即从索引 i 到 j 的闭区间)中,能获得的最大得分。注意,这里我们考虑的是不要求连续的子序列。 状态转移: 情况1:不考虑字符 i。那么最大得分就是 dp[ i+1][ j ]。 情况2:如果 s[ i] 是 '(',我们尝试为它匹配一个在位置 k (i < k <= j) 的 ')',使得 s[ k ] 是 ')'。这样,我们可以将区间分成三部分: 内部区间 [ i+1, k-1]:这是一个合法的括号序列,得分是 dp[ i+1][ k-1 ]。 匹配的括号对 (i, k):得分是 score[ i] + score[ k ]。 外部区间 [ k+1, j]:得分是 dp[ k+1][ j ]。 总得分是这三部分的和。我们需要遍历所有可能的 k,取最大值。 此外,区间 [ i, j] 可能由两个合法的括号序列拼接而成,即存在一个分割点 m (i <= m < j),使得总得分 = dp[ i][ m] + dp[ m+1][ j ]。我们也需要遍历所有可能的 m,取最大值。 初始化:对于长度为0的区间(即 i > j),dp[ i][ j] = 0。对于长度为1的区间,由于单个字符无法形成合法的括号对(除非是空,但空序列得分0),所以 dp[ i][ i ] = 0。 计算顺序:由于 dp[ i][ j ] 依赖于更短的区间(即区间长度更小),所以我们按区间长度 len 从小到大进行计算,从 len=2 开始(因为至少需要两个字符才能形成一对括号)。 最终答案:整个字符串 s[ 0:n-1] 的最大得分就是 dp[ 0][ n-1 ]。 举例说明: 假设 s = "()()", score = [ 1, 2, 3, 4 ]。 区间长度2: [ 0,1]: s[ 0]='(', s[ 1]=')',匹配,得分=1+2=3。dp[ 0][ 1 ]=3。 [ 1,2]: s[ 1]=')', s[ 2]='(',无法匹配,dp[ 1][ 2 ]=0。 [ 2,3]: s[ 2]='(', s[ 3]=')',匹配,得分=3+4=7。dp[ 2][ 3 ]=7。 区间长度4:[ 0,3 ]: 情况1:不考虑s[ 0],得分=dp[ 1][ 3]。需要计算dp[ 1][ 3]:区间[ 1,3]=")(",内部无法形成合法序列,但可以分割为[ 1,2]和[ 3,3](但dp[ 3][ 3]=0),所以dp[ 1][ 3 ]=0。 情况2:s[ 0 ]='(',尝试匹配k=1,3。 k=1:内部[ 1,0]无效(得分0),匹配得分=1+2=3,外部[ 2,3 ]得分=7,总=10。 k=3:内部[ 1,2]=")(",dp[ 1][ 2 ]=0,匹配得分=1+4=5,外部无,总=5。 最大值10。 情况3:分割点m=1:dp[ 0][ 1]+dp[ 2][ 3 ]=3+7=10。 所以dp[ 0][ 3 ]=max(0, 10, 10)=10。 最终最大得分是10,对应的子序列是取整个字符串"()()"。