题目链接:https://ac.nowcoder.com/acm/contest/926/B
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
给定一个长度为 L ( L 为偶数)的字符串 S ,且串中只包含’(’ 和‘)’。
现在每次对该串的操作可以选择以下之一:
- 选择 S 中的一个’(’并将其替换为’)’
- 选择 S 中的一个’)’并将其替换为’(’
- 选择 S 中的一个”()”子串并将该子串从 S 串中移除
求至少经过多少次操作可以使得 S 变为空串。
输入描述:
一行一个长度为 L的字符串,保证 L为偶数,且只含’(’和‘)’。
输出描述:
一行一个整数—最小的操作次数
示例1
输入
()))()
输出
4
说明
可以通过 4次操作将串 S变为空串
“()))()”→“()))”→“))”→“()”→“”
示例2
输入
))((
输出
4
备注:
数据范围及约束条件
解题思路:
先将"()"子串取出,操作数(ans)加一,然后剩下的偶数个括号中肯定是右括号')'在左,左括号'('在右,无法看做"()"取出,所以需要将部分左/右括号变为右/左括号,和原先另一部分左/右括号形成"()",然后取出,例如:将"))))(((("→"()))(((("→"()()(((("→"()()()(("→"()()()()",然后再将"()"子串取出,偶数对很容易可以看出需要s.length()次操作,如果是奇数对,例如:")))((("→"())((("→"())(()"→ "()((()"→"()()()",很容易可以看出奇数对需要s.length()+1次操作,但是,很悲剧的是。。。这个思路它不太对,并不是所有的s去完"()"后都是"))(("、")))((("这样的类型,也有可能有"(((("或者"))))",这时候就出问题了,所以这个思路不好 (T▽T)
那么我们就换一种思路,遍历一遍s,用一个f记录一下在当前位置右边有多少左括号,当遇到左括号时,f++,当遇到右括号时,如果f不为0,则说明他可以和一个左括号匹配成"()",所以f--,操作数(ans)++,如果f为0,则说明右边没有能匹配的左括号,所以将这个右括号变成左括号,然后f++,操作数(ans)++,遍历完之后,肯定只剩下f个左括号,这时候只要讲其中一半变为右括号,然后移除就好,所以操作数(ans)+f,这就是最终答案了;
有问题的代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
using namespace std;
int main(){
string s;
cin>>s;
long long ans = 0;
//遍历一遍,先将s中的"()"去掉
for(int i = 0; i < s.length(); i++){
if(s[i] == '(' && s[i+1] == ')'){
ans++;
s.erase(i,2);
i-=(i>=1?2:1);
}
}
//判断剩下的s是奇数对还是偶数队
if( (s.length()/2)%2 == 0){
ans+=s.length() ;
}
else{
ans+=(s.length()+1);
}
printf("%d\n",ans);
return 0;
}
正确思路的代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
using namespace std;
int main(){
string s;
cin>>s;
long long ans = 0;
int f = 0;
for(int i = 0; i < s.length(); i++){
if(s[i] == '('){ //如果是左括号,f++
f++;
}
else{
if(f == 0){ //如果是右括号,而且右边没有左括号了,将这个右括号变为左括号
ans++;
f++;
}
else{ //如果右边有左括号,和左括号形成"()"移除
ans++;
f--;
}
}
}
ans+=f; //将剩下的左括号中的一半变为右括号,然后移除,正好需要f次操作
printf("%lld\n",ans);
return 0;
}