括号插入的最小成本问题(相邻括号匹配代价)
字数 1809 2025-12-01 09:02:45

括号插入的最小成本问题(相邻括号匹配代价)

题目描述
给定一个由字符 '(' 和 ')' 组成的字符串 s,你可以在任意位置插入任意数量的括号('(' 或 ')'),每次插入的成本为 1。你的目标是插入最少的括号,使得整个字符串变成有效的括号序列。有效括号序列的定义是:空字符串是有效的;如果 A 和 B 是有效的,那么 AB 也是有效的;如果 A 是有效的,那么 (A) 也是有效的。请计算最小插入成本。

解题过程

  1. 问题分析
    这是一个典型的区间动态规划问题。我们需要将整个字符串划分为子区间,逐步计算每个子区间变成有效括号序列的最小成本。关键在于如何定义状态和状态转移方程。

  2. 状态定义
    设 dp[i][j] 表示将子串 s[i:j+1](即从索引 i 到 j 的子串)变成有效括号序列的最小插入成本。我们的目标是计算 dp[0][n-1],其中 n 是字符串 s 的长度。

  3. 基础情况

    • 当子串长度为 0(即 i > j)时,空字符串本身就是有效的,成本为 0:dp[i][j] = 0(若 i > j)。
    • 当子串长度为 1 时,单个字符无法形成有效括号,需要插入一个匹配的括号,成本为 1:dp[i][i] = 1。
  4. 状态转移方程
    对于子串 s[i:j+1],我们考虑两种可能的情况:

    • 情况1:s[i] 和 s[j] 可以匹配(即 s[i] 是 '(' 且 s[j] 是 ')')。如果它们匹配,那么我们可以先处理内部子串 s[i+1:j](即从 i+1 到 j-1 的部分),成本为 dp[i+1][j-1]。但注意:s[i] 和 s[j] 本身已经存在,不需要额外插入成本来匹配它们,因此 dp[i][j] 可能等于 dp[i+1][j-1]。
    • 情况2:无论 s[i] 和 s[j] 是否匹配,我们都可以将子串分割成两部分:s[i:k+1] 和 s[k+1:j+1](其中 i ≤ k < j)。总成本是两部分成本之和:dp[i][k] + dp[k+1][j]。我们需要遍历所有可能的分割点 k,取最小值。

    综合以上情况,状态转移方程为:
    dp[i][j] = min(
    dp[i+1][j-1] 如果 s[i] 和 s[j] 匹配,
    min(dp[i][k] + dp[k+1][j]) 对于所有 k 从 i 到 j-1
    )

  5. 计算顺序
    由于 dp[i][j] 依赖于更短的子区间(如 dp[i+1][j-1] 和 dp[i][k]、dp[k+1][j]),我们需要按子串长度从小到大计算。具体顺序:

    • 首先处理长度为 1 的子串(基础情况)。
    • 然后依次处理长度为 2, 3, ..., n 的子串。
  6. 示例演算
    以 s = "())" 为例(n=3):

    • 初始化:所有长度为 1 的子串成本为 1(dp[0][0]=1, dp[1][1]=1, dp[2][2]=1)。
    • 长度 2 的子串:
      • s[0:2] = "()":s[0]='(' 和 s[1]=')' 匹配,dp[0][1] = dp[1][0](空串成本为 0) = 0。
      • s[1:3] = "))":s[1]=')' 和 s[2]=')' 不匹配,需分割:min(dp[1][1]+dp[2][2]=1+1=2) → dp[1][2]=2。
    • 长度 3 的子串 s[0:3] = "())":
      • 检查首尾:s[0]='(' 和 s[2]=')' 匹配,但内部子串 s[1:2] = ")" 成本为 dp[1][1]=1,所以候选值1为 1。
      • 分割点 k=0:dp[0][0]+dp[1][2]=1+2=3;k=1:dp[0][1]+dp[2][2]=0+1=1。
      • 最小值是 min(1, 3, 1) = 1。
    • 最终结果:dp[0][2] = 1。
  7. 算法实现要点

    • 时间复杂度 O(n³),空间复杂度 O(n²)。
    • 注意边界条件(如空串处理)。
    • 实际代码中,可通过循环长度 len 从 1 到 n,然后遍历起始点 i,计算 j = i + len - 1。

通过以上步骤,我们可以系统地计算出任意字符串的最小插入成本,确保括号序列有效。

括号插入的最小成本问题(相邻括号匹配代价) 题目描述 给定一个由字符 '(' 和 ')' 组成的字符串 s,你可以在任意位置插入任意数量的括号('(' 或 ')'),每次插入的成本为 1。你的目标是插入最少的括号,使得整个字符串变成有效的括号序列。有效括号序列的定义是:空字符串是有效的;如果 A 和 B 是有效的,那么 AB 也是有效的;如果 A 是有效的,那么 (A) 也是有效的。请计算最小插入成本。 解题过程 问题分析 这是一个典型的区间动态规划问题。我们需要将整个字符串划分为子区间,逐步计算每个子区间变成有效括号序列的最小成本。关键在于如何定义状态和状态转移方程。 状态定义 设 dp[ i][ j] 表示将子串 s[ i:j+1](即从索引 i 到 j 的子串)变成有效括号序列的最小插入成本。我们的目标是计算 dp[ 0][ n-1 ],其中 n 是字符串 s 的长度。 基础情况 当子串长度为 0(即 i > j)时,空字符串本身就是有效的,成本为 0:dp[ i][ j ] = 0(若 i > j)。 当子串长度为 1 时,单个字符无法形成有效括号,需要插入一个匹配的括号,成本为 1:dp[ i][ i ] = 1。 状态转移方程 对于子串 s[ i:j+1 ],我们考虑两种可能的情况: 情况1 :s[ i] 和 s[ j] 可以匹配(即 s[ i] 是 '(' 且 s[ j] 是 ')')。如果它们匹配,那么我们可以先处理内部子串 s[ i+1:j](即从 i+1 到 j-1 的部分),成本为 dp[ i+1][ j-1]。但注意:s[ i] 和 s[ j] 本身已经存在,不需要额外插入成本来匹配它们,因此 dp[ i][ j] 可能等于 dp[ i+1][ j-1 ]。 情况2 :无论 s[ i] 和 s[ j] 是否匹配,我们都可以将子串分割成两部分:s[ i:k+1] 和 s[ k+1:j+1](其中 i ≤ k < j)。总成本是两部分成本之和:dp[ i][ k] + dp[ k+1][ j ]。我们需要遍历所有可能的分割点 k,取最小值。 综合以上情况,状态转移方程为: dp[ i][ j ] = min( dp[ i+1][ j-1] 如果 s[ i] 和 s[ j ] 匹配, min(dp[ i][ k] + dp[ k+1][ j ]) 对于所有 k 从 i 到 j-1 ) 计算顺序 由于 dp[ i][ j] 依赖于更短的子区间(如 dp[ i+1][ j-1] 和 dp[ i][ k]、dp[ k+1][ j ]),我们需要按子串长度从小到大计算。具体顺序: 首先处理长度为 1 的子串(基础情况)。 然后依次处理长度为 2, 3, ..., n 的子串。 示例演算 以 s = "())" 为例(n=3): 初始化:所有长度为 1 的子串成本为 1(dp[ 0][ 0]=1, dp[ 1][ 1]=1, dp[ 2][ 2 ]=1)。 长度 2 的子串: s[ 0:2] = "()":s[ 0]='(' 和 s[ 1]=')' 匹配,dp[ 0][ 1] = dp[ 1][ 0 ](空串成本为 0) = 0。 s[ 1:3] = "))":s[ 1]=')' 和 s[ 2]=')' 不匹配,需分割:min(dp[ 1][ 1]+dp[ 2][ 2]=1+1=2) → dp[ 1][ 2 ]=2。 长度 3 的子串 s[ 0:3 ] = "())": 检查首尾:s[ 0]='(' 和 s[ 2]=')' 匹配,但内部子串 s[ 1:2] = ")" 成本为 dp[ 1][ 1 ]=1,所以候选值1为 1。 分割点 k=0:dp[ 0][ 0]+dp[ 1][ 2]=1+2=3;k=1:dp[ 0][ 1]+dp[ 2][ 2 ]=0+1=1。 最小值是 min(1, 3, 1) = 1。 最终结果:dp[ 0][ 2 ] = 1。 算法实现要点 时间复杂度 O(n³),空间复杂度 O(n²)。 注意边界条件(如空串处理)。 实际代码中,可通过循环长度 len 从 1 到 n,然后遍历起始点 i,计算 j = i + len - 1。 通过以上步骤,我们可以系统地计算出任意字符串的最小插入成本,确保括号序列有效。