上次用自底向上递推的姿势Copy-Study了这道题的题解。但是还有一个个人觉得更容易接受的姿势——记忆化搜索。
思路:递归+记忆化
记忆存在:return d[i][j]
递归边界1:i > j——此时不需要添加括号,return 0
递归边界2:i == j——此时是单个的,只需添加一个括号即可匹配,return 1
初始化ans = ∞
匹配:内部需要添加的括号为可能的解
暴搜:枚举 i~j 之间的k,找到最小的dfs(i, k) + dfs(k+1, j)
vis[i][j] = true
return d[i][j] = ans
而对于打印解,依然靠pos[ ][ ]数组记录最优分界点。
代码如下:
/****************************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <string>
#include <iostream>
using namespace std;
/****************************************/
const int N = 105, SUP = 2e9;
int d[N][N], pos[N][N];
bool vis[N][N];
char s[N];
int dfs(int i, int j)
{
if(vis[i][j])
return d[i][j];
if(i > j)
return 0;
if(i == j)
return 1;
int ans = SUP;
if((s[i] == '(' && s[j] == ')') || (s[i] == '[' && s[j] == ']')) {
ans = min(ans, dfs(i+1, j-1));
pos[i][j] = -1;
}
for(int k = i; k < j; k++) {
int u = dfs(i, k) + dfs(k+1, j);
if(ans > u) {
ans = u;
pos[i][j] = k;
}
}
vis[i][j] = true;
return d[i][j] = ans;
}
void PR(int l, int r)
{
if(l > r) return ;
if(l == r) {
if(s[l] == '(' || s[l] == ')')
printf("()");
else
printf("[]");
}
else {
if(pos[l][r] == -1) {
putchar(s[l]);
PR(l+1, r-1);
putchar(s[r]);
}
else {
PR(l, pos[l][r]);
PR(pos[l][r]+1, r);
}
}
}
int main()
{
memset(vis, 0, sizeof(vis));
scanf("%s", s);
int len = strlen(s);
dfs(0, len-1);
PR(0, len-1);
putchar('\n');
return 0;
}

本文介绍了一种使用记忆化搜索解决括号匹配问题的方法,通过递归与记忆化减少重复计算,提高了解决效率。同时,文章还详细阐述了如何利用pos[][]数组记录最优分界点来优化打印解的过程。
4198

被折叠的 条评论
为什么被折叠?



