题意
输入n个括号(只有左括号和右括号两种),最多允许移动一个括号,问能否实现括号匹配。
分析
这个题令我比较恼火,想多了,自己思路固定在用栈匹配中出不来了。
一开始想的是,先进行匹配,如果某种括号剩下两个,即可经过移动达到要求。这个需要单独考虑右括号在开头的情况。不知道为什么,我的代码总是错误。只好重换思路
错误代码
#include<bits/stdc++.h>
using namespace std;
stack<int>q;
int main()
{
int i,j;
int cnt=0,num1=0,num2=0,flag=0;
string ch;
scanf("%d",&i);
cin>>ch;
for(j=0;j<i;j++)
{
if(ch[j]==')')
num1++;
else
num2++;
}
if(i==2)
{
printf("Yes\n");
return 0;
}
int temp;
temp=abs(num1-num2);
if(temp!=2&&temp!=0)
{
printf("No\n");
return 0;
}
//printf("%d %d\n",num1,num2);
for(j=0;j<i;j++)
{ cnt++;
if(ch[j]=='(')
{
q.push(cnt);
}
if(ch[j]==')')
{
if(flag==0&&q.empty())
{
flag=1;q.push(cnt);num1--;num2++;continue;
}
else if(flag==1&&q.empty())
{
printf("No\n");
return 0;
}
q.pop();
num1--;num2--;
}
if((num2==0)&&(num1==2||num1==0))
{
printf("Yes\n");
return 0;
}
else if(num1==0&&(num2==2||num2==0))
{
printf("Yes\n");
return 0;
}
}
printf("No\n");
return 0;
}
后来借鉴了网上大神的思路。不用栈匹配,直接用num来标记。一个左括号要和一个右括号相对应,相当于消除。遇到左括号,num++;右括号,num- -。再用一个mm记录经过消除后,右括号最左边的位置。如果mm==-1,说明在尚未匹配的队列中,右括号在最前面,且其后面就是左括号。这样是可以经过移动后形成匹配的。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int mm,num=0,n;
char ch[200050];
cin>>n>>ch;
int i,j;
mm=n;
for(i=0;i<n;i++)
{
if(ch[i]=='(')
num++;//相当于压栈,将左括号压入栈中
else
num--;//相当于出栈,每次最后压入的左括号都与第一个右括号相抵消
mm=min(mm,num);//记录抵消后的第一个右括号的位置
}
if(num==0&&mm>=-1)//左右括号相等并且可以移动匹配
printf("Yes\n");
else
printf("No\n");
return 0;
}