原题链接:码题集OJ-括号
题目大意:给一个由 '(' 和 ')' 构成的字符串,对于这个字符串可以最多翻转一个字符,让这个括号序列相互匹配,匹配是指从左到右,每一个左括号都能够对应一个右括号。问有几个可以翻转的位置?
思路:因为最多翻转一个位置,那么可以记录一下(的数量和)的数量,如果数量相等那么就是不用翻转的字符串,那么答案就是0。如果(的数量大于)的数量,那么就需要逆序的遍历字符串,因为能够消除)的括号一定在左边,如果遍历到了)那么就记录一下当前)的总和,如果是(那么如果)存在,那么答案就加一,并且)的数量减去1,如果)的数量为负数就跳出去。如果)的数量大于(就是同上面相反的思路。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const int N=1e6+10;
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
string s;cin>>s;
ll sum1=0,sum2=0;
for(auto i:s)
{
if(i=='(')sum1++;
else sum2++;
}
ll ans=0,sum=0;
/*
sum为已经扫描过的字符串剩下的能够用来匹配的括号,当遇见相同的括号时数量加一,如果遇见了不同的括号,数量就会减去1。
如果sum>0,并且当前的括号和sum代表的括号不同,那么当前位置的括号就可以翻转。
因为已经扫描过的字符串是不翻转匹配的,而且必须翻转一次,所以当前的位置可以翻转。
到下一个位置的时候,将sum减一就代表之前扫描的位置为不翻转匹配的。
如果sum为0,并且当前点的括号和sum代表的不同,那么当前点的括号就不能匹配,所以需要翻转。
当这个位置之后,已经扫描的字符串就不是匹配的字符串了,之后再修改无法影响到之前的字符串,所以直接跳出
*/
if(sum1>sum2)
{
for(int i=s.size()-1;i>=0;i--)
{
if(s[i]==')')sum++;
else
{
ans++;
if(sum==0)break;
sum--;
}
}
}
else if(sum1<sum2)
{
for(int i=0;i<s.size();i++)
{
if(s[i]=='(')sum++;
else
{
ans++;
if(sum==0)break;
sum--;
}
}
}
cout<<ans;
return 0;
}