题意:
给出\(N\)个字符串,全都是由(
和)
组成的,判断\(S_1,S_2.....S_n\)能否以合理的顺序,满足其中的(
和)
配对成功。(注意配对的(
和)
一定是(
在前,)
在后).
思路:
首先这是个字符串匹配问题,我们就可以将其转化成(
为1,)
为-1.这样就将一个字符串转化两个有意义的值,一个是最小前缀值(就是前面有多少个没有匹配的)
)我们用MinNum来表示,还有一个就是字符串的值(也就是整个字符串需要多少个其他(
,或者)
来中和)我们用Num来表示.举个例子( ( ) ) ) ) ((
,MinNum = -2 Num = 0.
显然我们从头分配字符串的话不能有前缀小于0,如果有就说明前面有)
没有匹配,就一定不符合条件.并且最后所有字符串都放上之后,最终的值一定是0,不然就说明还有(
没有中和掉.
假设TotalNum是遍历到字符串\(S_i\)之前的数字和,那么要求TotalNum+MinNum >= 0
,满足条件就更新TotalNum,新的TotalNum=TotalNum+Num
。
那么如何排序字符串\(S_i\),保证尽可能满足这个条件呢?
显然可以按照minNum从大到小进行排列(totalNum>0),但是totalNum >0和totalNum < 0 显然是两种情况,应该分开来讨论,所以说设置两个数组v1,v2一个用来存储totalNum>0,一个用来存储totalNum < 0,那么最终两个数组v1和v2的TotalNum应该互为相反数。
这里我说下\(v_2\)为什么加进去的是 v2.push_back({minNum-num,-num});//都转化成反方向
其实就是想到与转成反方向,例如(()))()))((
MinNum=-3,Num=-1;
他就相当于))((()((())
MinNum= -2 Num=1;
这个地方就是不好理解.
vector<pii> v1;
vector<pii> v2;
void solve()
{
ll n;
scanf("%lld",&n);
for(int i=1;i<=n;i++){
string str;
cin>>str;
ll minNum=1e9+7,num=0;
for(int j=0;j<str.size();j++){
if(str[j]=='('){
num++;
}else {
num--;
}
minNum=min(minNum,num);
}
if(num>0) v1.push_back({minNum,num});
else v2.push_back({minNum-num,-num});//都转化成反方向
}
sort(v1.begin(),v1.end());
sort(v2.begin(),v2.end());
reverse(v1.begin(),v1.end());
reverse(v2.begin(),v2.end());
ll now=0;
for(int i=0;i<v1.size();++i){
if(now+v1[i].x<0){
puts("No");
return ;
}
now=now+v1[i].y;
}
ll now1=0;
for(int i=0;i<v2.size();i++){
if(now1+v2[i].x<0){
puts("No");
return ;
}
now1=now1+v2[i].y;
}
if(now!=now1) {
puts("No");
return ;
}
puts("Yes");
}