从1向2*n枚举字符串的元素,用栈保存遇到的左括号(还没和右括号匹配的),遇到右括号的时候,
如果栈中有元素(左括号),那么它是能和 枚举到的右括号匹配的,
那么就弹出这个左括号。
如果栈中没有元素(没有还没被匹配的左括号),那么这个右括号就是孤身一人的,
会影响它所在子括号序列的合法性。
我用 f[ i ] 来标记所有孤身一人的,可怜的右括号。( f [ i ] = 1 )
这些光棍会把整个序列分为好几段,
光棍1前面的序列是合法的,
光棍1到光棍2之间的序列是合法的
光棍2到光棍3之间的序列是合法的
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
char s[2*N];
int f[2*N];
int mat[2*N];
int st[2*N];
int stk[2*N],top;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=2*n;i++)
{
f[i]=0;
mat[i]=0;
st[i]=false;
}
scanf("%s",s+1);
top=0;
int v;
for(int i=1;i<=2*n;i++)
{
if(s[i]=='(')
{
stk[++top]=i;
}
else if(s[i]==')')
{
if(top>=1)
{
int tt=stk[top--];
mat[i]=tt;
}
else if(top==0)
{
f[i]=1;
}
}
}
int sum=0;
//匹配起来
int pz=-1;
for(int i=1;i<=2*n;i++)
{
if(s[i]=='(')
{
if(i==1||s[i-1]==')')
{
if(pz==-1)
{
pz=i;
if(!st[pz])
{
st[pz]=pz;
sum++;
}
}
else
{
st[i]=pz;
}
}
}
else if(s[i]==')')
{
if(f[i])
{
pz=-1;
}
}
}
for(int i=1;i<=2*n;i++)
{
if(s[i]==')')
{
//x和i
int x=mat[i];
if(!st[x]&&!st[i])
{
sum++;
st[x]=x;
st[i]=x;
}
else if(st[x]&&!st[i])
{
st[i]=st[x];
}
else if(!st[x]&&st[i])
{
st[x]=st[i];
}
}
}
printf("%d\n",sum);
}
return 0;
}