括号插入的最小成本问题
字数 992 2025-11-22 00:34:48

括号插入的最小成本问题

题目描述:
给定一个由"("、")"和"a"组成的字符串s,以及两个整数x和y。字符串中可能包含不匹配的括号。你可以执行两种操作:

  1. 在任意位置插入一个"(",成本为x
  2. 在任意位置插入一个")",成本为y

你的目标是通过最少的成本插入括号,使得整个字符串变成有效的括号序列。

解题过程:

步骤1:问题分析

  • 有效的括号序列要求:每个左括号都有对应的右括号,且匹配顺序正确
  • 我们需要在适当位置插入括号来修正不匹配的情况
  • 插入左括号成本为x,插入右括号成本为y

步骤2:定义状态
设dp[i][j]表示将子串s[i...j]变成有效括号序列的最小成本。

步骤3:状态转移方程
情况1:如果s[i]是右括号")",我们有两种选择:

  • 在i前面插入一个左括号与之匹配,成本为x + dp[i+1][j]
  • 删除s[i](相当于插入右括号来匹配前面的左括号),成本为y + dp[i+1][j]

情况2:如果s[i]是左括号"(",我们需要找到与之匹配的右括号:

  • 遍历所有可能的k(i < k ≤ j),如果s[k]是右括号")",那么:
    dp[i][j] = min(dp[i][j], dp[i+1][k-1] + dp[k+1][j])
  • 或者我们也可以选择不匹配,直接插入右括号:dp[i][j] = min(dp[i][j], y + dp[i+1][j])

情况3:对于任意区间[i,j],我们还可以考虑分割点:
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j]),其中i ≤ k < j

步骤4:边界条件

  • 当i > j时,dp[i][j] = 0(空字符串已经是有效的)
  • 当i = j时:
    • 如果是"(",需要插入右括号,成本为y
    • 如果是")",需要插入左括号,成本为x
    • 如果是"a",需要插入一对括号,成本为min(x+y, 2x, 2y)中的最小值

步骤5:算法实现
我们使用自底向上的方法,按区间长度从小到大计算:

def minCostToMakeValid(s: str, x: int, y: int) -> int:
    n = len(s)
    dp = [[0] * (n + 1) for _ in range(n + 1)]
    
    # 初始化长度为1的区间
    for i in range(n):
        if s[i] == '(':
            dp[i][i] = y  # 需要插入右括号
        elif s[i] == ')':
            dp[i][i] = x  # 需要插入左括号
        else:  # 'a'
            dp[i][i] = min(x + y, 2 * x, 2 * y)
    
    # 按区间长度从小到大计算
    for length in range(2, n + 1):
        for i in range(n - length + 1):
            j = i + length - 1
            # 初始化为一个较大值
            dp[i][j] = float('inf')
            
            # 情况1:s[i]是右括号
            if s[i] == ')':
                dp[i][j] = min(dp[i][j], x + dp[i+1][j])  # 插入左括号
                dp[i][j] = min(dp[i][j], y + dp[i+1][j])  # 插入右括号(删除当前)
            
            # 情况2:s[i]是左括号  
            elif s[i] == '(':
                dp[i][j] = min(dp[i][j], y + dp[i+1][j])  # 插入右括号
                # 尝试匹配
                for k in range(i + 1, j + 1):
                    if s[k] == ')':
                        dp[i][j] = min(dp[i][j], dp[i+1][k-1] + dp[k+1][j])
            
            # 情况3:s[i]是字符'a'
            else:
                # 可以当作左括号、右括号,或者普通字符处理
                dp[i][j] = min(dp[i][j], x + dp[i+1][j])  # 当作右括号,插入左括号
                dp[i][j] = min(dp[i][j], y + dp[i+1][j])  # 当作左括号,插入右括号
                # 尝试匹配
                for k in range(i + 1, j + 1):
                    if s[k] == ')' or s[k] == 'a':  # 'a'可以当作右括号
                        dp[i][j] = min(dp[i][j], dp[i+1][k-1] + dp[k+1][j])
            
            # 情况4:分割区间
            for k in range(i, j):
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j])
    
    return dp[0][n-1]

步骤6:复杂度分析

  • 时间复杂度:O(n³),需要三重循环
  • 空间复杂度:O(n²),用于存储dp表

步骤7:优化考虑
可以通过预处理来优化匹配查找,将时间复杂度优化到O(n²),但基本的区间DP思路如上所述。

括号插入的最小成本问题 题目描述: 给定一个由"("、")"和"a"组成的字符串s,以及两个整数x和y。字符串中可能包含不匹配的括号。你可以执行两种操作: 在任意位置插入一个"(",成本为x 在任意位置插入一个")",成本为y 你的目标是通过最少的成本插入括号,使得整个字符串变成有效的括号序列。 解题过程: 步骤1:问题分析 有效的括号序列要求:每个左括号都有对应的右括号,且匹配顺序正确 我们需要在适当位置插入括号来修正不匹配的情况 插入左括号成本为x,插入右括号成本为y 步骤2:定义状态 设dp[ i][ j]表示将子串s[ i...j ]变成有效括号序列的最小成本。 步骤3:状态转移方程 情况1:如果s[ i ]是右括号")",我们有两种选择: 在i前面插入一个左括号与之匹配,成本为x + dp[ i+1][ j ] 删除s[ i](相当于插入右括号来匹配前面的左括号),成本为y + dp[ i+1][ j ] 情况2:如果s[ i ]是左括号"(",我们需要找到与之匹配的右括号: 遍历所有可能的k(i < k ≤ j),如果s[ k ]是右括号")",那么: dp[ i][ j] = min(dp[ i][ j], dp[ i+1][ k-1] + dp[ k+1][ j ]) 或者我们也可以选择不匹配,直接插入右括号:dp[ i][ j] = min(dp[ i][ j], y + dp[ i+1][ j ]) 情况3:对于任意区间[ i,j ],我们还可以考虑分割点: dp[ i][ j] = min(dp[ i][ j], dp[ i][ k] + dp[ k+1][ j]),其中i ≤ k < j 步骤4:边界条件 当i > j时,dp[ i][ j ] = 0(空字符串已经是有效的) 当i = j时: 如果是"(",需要插入右括号,成本为y 如果是")",需要插入左括号,成本为x 如果是"a",需要插入一对括号,成本为min(x+y, 2x, 2y)中的最小值 步骤5:算法实现 我们使用自底向上的方法,按区间长度从小到大计算: 步骤6:复杂度分析 时间复杂度:O(n³),需要三重循环 空间复杂度:O(n²),用于存储dp表 步骤7:优化考虑 可以通过预处理来优化匹配查找,将时间复杂度优化到O(n²),但基本的区间DP思路如上所述。