题目链接:Problem - 1837D - Codeforces
题意理解:
判断是否可以将字符串s分成若干字子串,使每个子串或每个翻转的子串是合法的括号序列。
预备知识:
首先要知道如何判断一个括号序列是否是合法,共有两个条件:
1.左括号数=右括号数
2.对于任意位置i,i前的左括号数一定大于等于右括号数(即右括号数不大于左括号数)
解题思路:
这个字符串最终一定会分为两个部分,一部分是不翻转就合法的,另一部分是需要翻转才合法的(每部分都可能为空)。
思路一:
首先判断整个字符串是否是一个合法的括号序列,如果他不是,输出-1;
对于每一个位置,那么如果前面左括号多,那么将它放到无需翻转的子串中,否则,放到需要翻转的子串中。
但是感觉这种思路的合理性证明不好解释,又用了思路二。
代码:
#include<iostream>
using namespace std;
int T,n;
string s;
int ans[200005];
bool check()
{
int l=0,r=0;
for(int i=0;i<n;i++)
{
if(s[i]=='(') l++;
else r++;
}
if(l!=r) return false;
return true;
}
void solve()
{
cin>>n>>s;
//先进行合法性检验
if(!check())
{
cout<<"-1"<<endl;
return;
}
//初始化变量
int l=0,r=0;
for(int i=0;i<n;i++) ans[i]=0;
//先找一段最长的RBS序列
for(int i=0;i<n;i++)
{
if(s[i]=='(')
{
if(l>=r) ans[i]=1;
else ans[i]=2;
l++;
}
else
{
r++;
if(l>=r) ans[i]=1;
else ans[i]=2;
}
}
int cnt=1;
for(int i=1;i<n;i++)
{
if(ans[i]!=ans[0]) cnt=2;
}
cout<<cnt<<endl;
if(cnt==1) for(int i=0;i<n;i++) cout<<"1 ";
else for(int i=0;i<n;i++)
{
cout<<ans[i]<<" ";
}
cout<<endl;
}
int main()
{
//freopen("D:\\data.txt","r",stdin);
cin>>T;
while(T--)
{
solve();
}
return 0;
}
思路二:
首先判断这个序列1.是否合法?2.是否可以用一种颜色填充。
合法:左括号数等于右括号数
一种颜色填充:保证任意位置左括号数始终大于右括号数(整个字符串是一个合法括号序列) 或者 保证任意位置右括号数始终大于左括号数(将整个字符串翻转,是一个合法括号序列)
否则,他就一定需要两种颜色填充。
那么就要找一个最长合法子串,开一个栈S,对于每个位置:
如果是左括号,那么就直接压进去;
如果是右括号,那么判断栈顶是否为左括号,如果是左括号,那么就与栈顶的左括号匹配,一起出栈;否则,他前面就没有左括号了,他就是需要翻转位置。
到最后,栈一定是栈顶都是左括号,栈底都是右括号,如:“)))(((”这样的形式。
将这些位置填充为颜色2
代码:
#include<iostream>
#include<stack>
using namespace std;
const int N = 200005;
int n,T;
string s;
int ans[N];
stack<int>S;
void solve()
{
cin>>n>>s;
//先判断两个问题:1.是否合法 2.是否可以用一种颜色填充
int l=0,r=0;
bool sv1=true,sv2=true;
for(int i=0;i<n;i++)
{
if(s[i]=='(') l++;
else if(s[i]==')') r++;
if(r>l) sv1=false;
if(l>r) sv2=false;
}
if(l!=r)
{
cout<<"-1"<<endl;
return;
}
else if(sv1 || sv2)
{
cout<<"1"<<endl;
for(int i=0;i<n;i++) cout<<"1 ";
cout<<endl;
return;
}
for(int i=0;i<n;i++)
{
ans[i]=1;
if(s[i]=='(') S.push(i);
else
{
if(!S.empty() && s[S.top()]=='(') S.pop();
else S.push(i);
}
}
while(!S.empty())
{
ans[S.top()]=2;
S.pop();
}
cout<<"2"<<endl;
for(int i=0;i<n;i++) cout<<ans[i]<<" ";
cout<<endl;
}
int main()
{
//freopen("D:\\data.txt","r",stdin);
cin>>T;
while(T--) solve();
return 0;
}