洛谷P1944 最长括号匹配 题解
题意:对一个由(,),[,]括号组成的字符串,求出其中最长的括号匹配子串。具体来说,满足如下条件的字符串成为括号匹配的字符串:
1.
(),[]
是括号匹配的字符串。2.若
A
是括号匹配的串,则(A),[A]
是括号匹配的字符串。3.若
A
,B
是括号匹配的字符串,则AB
也是括号匹配的字符串。例如:
(),[],([]),()()
都是括号匹配的字符串,而][,[(])
则不是。字符串
A
的子串是指由A
中连续若干个字符组成的字符串。例如,
A,B,C,ABC,CAB,ABCABC
都是ABCABC
的子串。空串是任何字符串的子串。
似乎可以用栈模拟,但是这个太没劲了,考虑dp
设 d p [ i ] dp[i] dp[i] 表示以 s [ i ] s[i] s[i] 结尾的最长括号匹配长度
显然当 s [ i ] s[i] s[i] 为左括号时 d p [ i ] = 0 dp[i]=0 dp[i]=0
当 s [ i ] s[i] s[i] 为右括号时, d p [ i ] dp[i] dp[i] 一定与 d p [ i − 1 ] dp[i-1] dp[i−1] 有关
容易发现 s [ i − d p [ i − 1 ] ] s[i-dp[i-1]] s[i−dp[i−1]] 是 d p [ i − 1 ] dp[i-1] dp[i−1] 的起始字符
则当 s [ i − d p [ i − 1 ] − 1 ] s[i-dp[i-1]-1] s[i−dp[i−1]−1] 与 s [ i ] s[i] s[i] 合法匹配时,有
d p [ i ] = d p [ i − 1 ] + 2 + d p [ i − d p [ i − 1 ] − 2 ] dp[i]=dp[i-1]+2+dp[i-dp[i-1]-2] dp[i]=dp[i−1]+2+dp[i−dp[i−1]−2]
这里的 d p [ i − d p [ i − 1 ] − 2 ] dp[i-dp[i-1]-2] dp[i−dp[i−1]−2] 只需要一个例子就好理解了
[]([])
123456
假设此时为
d
p
[
5
]
=
2
dp[5]=2
dp[5]=2 ,对于以
s
[
5
]
s[5]
s[5] 结尾的最长括号匹配显然是[]
然后到了 d p [ 6 ] = 6 dp[6]=6 dp[6]=6 ,注意到此时 s [ 3 ] s[3] s[3] 被合法利用了,
这样就造成了 s [ 3 ] s[3] s[3] 之前的 d p [ 6 − d p [ 5 ] − 2 ] = d p [ 2 ] dp[6-dp[5]-2] = dp[2] dp[6−dp[5]−2]=dp[2] 被重新利用
应该很好理解了
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1e6+15)
int n,ans,dp[N],id;
char s[N];
signed main()
{
scanf("%s",(s+1));n=strlen(s+1);
for(int i=2; i<=n; i++)
{
if(s[i]=='('||s[i]=='[')continue;
else
{
if(s[i]==')'&&s[i-dp[i-1]-1]=='('||
s[i]==']'&&s[i-dp[i-1]-1]=='[')
{
dp[i]=dp[i-1]+2+dp[i-dp[i-1]-2];
if(dp[i]>ans)ans=dp[i],id=i;
}
}
}
for(int i=id-ans+1; i<=id; i++)
putchar(s[i]);
puts("");
return 0;
}
转载请说明出处