解题思路
-
状态定义:
- 表示使区间 的括号序列合法所需插入的最少括号数
-
转移方程:
- 当 和 匹配时:
- 否则:
代码
#include <bits/stdc++.h>
using namespace std;
int dp[105][105];
bool match(char left, char right) {
return (left == '(' && right == ')') || (left == '[' && right == ']');
}
int main() {
string s;
cin >> s;
int n = s.length();
// 初始化
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
dp[i][j] = n; // 初始化为最大可能值
}
dp[i][i] = 1; // 单个括号需要插入一个配对括号
}
// 处理长度为2的情况
for(int i = 0; i < n-1; i++) {
if(match(s[i], s[i+1])) {
dp[i][i+1] = 0; // 如果匹配,不需要插入
} else {
dp[i][i+1] = 2; // 不匹配,需要插入两个括号
}
}
// 区间dp
for(int len = 3; len <= n; len++) {
for(int i = 0; i + len - 1 < n; i++) {
int j = i + len - 1;
// 如果两端匹配
if(match(s[i], s[j])) {
dp[i][j] = dp[i+1][j-1];
} else {
// 在左端或右端插入一个括号
dp[i][j] = min(dp[i+1][j] + 1, dp[i][j-1] + 1);
}
// 枚举分割点
for(int k = i; k < j; k++) {
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j]);
}
}
}
cout << dp[0][n-1] << endl;
return 0;
}
import java.util.*;
public class Main {
static int[][] dp = new int[105][105];
static boolean match(char left, char right) {
return (left == '(' && right == ')') || (left == '[' && right == ']');
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int n = s.length();
// 初始化
for(int i = 0; i < n; i++) {
Arrays.fill(dp[i], n); // 初始化为最大可能值
dp[i][i] = 1; // 单个括号需要插入一个配对括号
}
// 处理长度为2的情况
for(int i = 0; i < n-1; i++) {
if(match(s.charAt(i), s.charAt(i+1))) {
dp[i][i+1] = 0;
} else {
dp[i][i+1] = 2;
}
}
// 区间dp
for(int len = 3; len <= n; len++) {
for(int i = 0; i + len - 1 < n; i++) {
int j = i + len - 1;
// 如果两端匹配
if(match(s.charAt(i), s.charAt(j))) {
dp[i][j] = dp[i+1][j-1];
} else {
// 在左端或右端插入一个括号
dp[i][j] = Math.min(dp[i+1][j] + 1, dp[i][j-1] + 1);
}
// 枚举分割点
for(int k = i; k < j; k++) {
dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k+1][j]);
}
}
}
System.out.println(dp[0][n-1]);
sc.close();
}
}
def match(left: str, right: str) -> bool:
return (left == '(' and right == ')') or (left == '[' and right == ']')
def solve(s: str) -> int:
n = len(s)
dp = [[n] * n for _ in range(n)] # 初始化为最大可能值
# 初始化单个括号的情况
for i in range(n):
dp[i][i] = 1
# 处理长度为2的情况
for i in range(n-1):
if match(s[i], s[i+1]):
dp[i][i+1] = 0
else:
dp[i][i+1] = 2
# 区间dp
for length in range(3, n+1):
for i in range(n-length+1):
j = i + length - 1
# 如果两端匹配
if match(s[i], s[j]):
dp[i][j] = dp[i+1][j-1]
else:
# 在左端或右端插入一个括号
dp[i][j] = min(dp[i+1][j] + 1, dp[i][j-1] + 1)
# 枚举分割点
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]
def main():
s = input().strip()
print(solve(s))
if __name__ == "__main__":
main()
算法及复杂度
- 算法:区间动态规划
- 时间复杂度:,其中 是字符串长度
- 空间复杂度:,用于存储 数组