传送门
关键思路:见了这种括号匹配的题,一是想栈,二是把见了左括号想成 + 1 +1 +1,见了右括号想成 − 1 -1 −1,从左向右特判每一位上的前缀和是不是 > = 0 >=0 >=0,以及最后一位的前缀和是不是 = 0 =0 =0
题解:因为给出的字符中只有一个左括号和右括号,字符总长度为 ∣ s ∣ |s| ∣s∣,那么必然要将 ∣ s ∣ − 2 |s|-2 ∣s∣−2个问号替换,因为这个字符串最后要匹配,也就是说比如见了左括号为 + 1 +1 +1,右括号为 − 1 -1 −1,那么必然到了每位上都不能为负值,为负值说明右括号多了呀,所以一种方法就是将前 ∣ s ∣ / 2 − 1 |s|/2-1 ∣s∣/2−1个问号全部替换为左括号,其余的问号全部替换为右括号,最后特判一遍即可。
rush(){
cin>>ori;
int len=ori.size(),cnt=len/2-1;
rep(i,0,len-1)ori[i]=(ori[i]!='?')?ori[i]:((cnt--)>0?'(':')');
int tmp=0;
bool flag=true;
rep(i,0,len-1){
tmp+=ori[i]=='('?1:-1;
if(tmp<0)flag=false;
}
if(tmp!=0)flag=false;
printf("%s\n",flag?"YES":"NO");
}
说下我的做法,我刚开始瞎看了一眼,没注意到题中说只有一个左括号和一个右括号,我以为有很多个左括号、右括号和问号,看了一眼数据范围 ∣ s ∣ < 100 |s|<100 ∣s∣<100,思路还是搞成 + 1 , − 1 +1,-1 +1,−1那种方法,那么也就说到了问号需要抉择是弄成左括号还是右括号呢,如果全部是左括号,最终无非就是到了 100 100 100,也就说到了每一位上能取到的值都在 200 200 200以内,那么循环数组处理下到了每一位上到底能取哪些值,见了左括号 + 1 +1 +1,见了右括号 − 1 -1 −1,见了问号分别处理 + 1 +1 +1和 − 1 -1 −1,最终特判即可
string s;
const int N=1e2+5;
int tmp[2][205];
int main(){
#ifdef io
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
rush(){
cin>>s;
int len=s.size();
bool flag=true;
rep(i,-100,100)tmp[0][i+100]=tmp[1][i+100]=0;
tmp[0][100]=1;
rep(i,1,len){
int now=i%2,up=(i-1)%2;
rep(j,-100,100)tmp[now][j+100]=0;
if(s[i-1]=='('){
rep(j,0,100){
if(tmp[up][j+100])tmp[now][j+1+100]=1;
}
}else if(s[i-1]==')'){
int ff=0;
rep(j,1,100){
if(tmp[up][j+100])tmp[now][j-1+100]=1,ff=1;
}
if(!ff){
flag=false;
break;
}
}else{
rep(j,-1,100)if(tmp[up][j+100])tmp[now][j+1+100]=1;
rep(j,1,100)if(tmp[up][j+100])tmp[now][j-1+100]=1;
}
}
if(!tmp[len%2][100])flag=false;
printf("%s\n",(flag?"YES":"NO"));
}
return 0;
}