题目
题目解析
关于去不去括号的探讨:
- 如果是(a+b)-c,发现括号可去,但是若(a+b)-(c+d)后面的括号括号又不可去。
- 若(ab)/c发现括号可去,但是(ab)/(c*d)后面的括号是不可去的。
- 经过大量对括号情况的枚举,我发现带括号的一般运算符的优先级是’/’ > ‘*’ > ‘-’ > ‘+’,若括号中最小的优先级比括号前后的优先级都要大或者是等于,则括号可去。而前两中情况就是单独列出来的特殊情况。
- 对特殊情况的说明:如果出现(a+b)-c,且 ‘(’ 前面的符号优先级小于等于 ‘+’,比如如果是a-(b+c)-d很明显括号不能去,但如果出现的是’ + ‘或者是’ ( '又或者前面没东西,这些情况都可以去掉括号,同理(a*b)/c也是如此
写代码的准备:
- 我们需要存储优先级,明显可以用hash表对运算符的映射得到。
- 我们需要判断括号内外的优先级,这里可以通过栈来进行相关操作。
- 我们需要删除括号,C++中可以直接把字符改为’\0’或者0,相当于删除了,因为string类是通过多次C风格的字符串拼接形成的。
其实有过数据结构栈的学习基础的,一般对括号相关的问题,应该都能想到去用栈来处理
逐行解析的代码
//整体思路:什么时候括号可去呢?括号中的最小优先级的运算符,它的优先级如果大于等于括号前后的优先级,括号可去。
#include <bits/stdc++.h>
using namespace std;
int main(){
string s;
//数组模拟hash
int level[256];
memset(level,0,sizeof(level));
//设置优先级,在带括号的优先级中,'/'明显优先级最高,而'+'优先级是最低的(这方面可以自己尝试)
level['/']=4;level['*']=3;level['-']=2;level['+']=1;
cin>>s;
//把括号和其中的运算符的位置入栈进行相关操作
stack<int> stack;
for(int i=0;i<s.length();i++){
if(s[i]=='(' || s[i]=='+' || s[i]=='-'
|| s[i]=='*' || s[i]=='/'){
stack.push(i);
}//一旦碰到右括号,开始出栈更新各优先级
else if(s[i]==')'){
int minLevel=5;
//更新中间的最小优先级
while(s[stack.top()]!='('){
minLevel = min(minLevel,level[s[stack.top()]]);
stack.pop();
}
//创建用于更新前后优先级的变量,默认优先级是最低的
int before = -1;
int after = -1;
//判断后面是否有运算符,如果有更新优先级
if(i+1<s.length() && s[i+1]!=')'){
after = level[s[i+1]];
}
//判断前面是否有运算符,如果有更新优先级
if(stack.top()-1>=0 && s[stack.top()-1]!='('){
before = level[s[stack.top()-1]];
}
//中间的优先级满足同时大于或等于前后的优先级,则该括号可以去掉
if(minLevel>=after && minLevel>=before){
//让s[i]=>右括号,s[stack.top()]=>左括号等于'\0'即可,
//因为在C++中string容器可以看作是多个字符串所拼接而成的,一旦遇到'\0'表示该段字符串结束,但还会继续读取后续被拼接的字符串,不然也是无法重载'+'运算符的。
s[i] = s[stack.top()] = 0;
}//处理特殊情况:1.当(a+b)-y时括号可去,其中'('的前面必须是优先级小于等于'+'
// 2. 当(x*y)/t括号可去,其中'('的前面优先级必须小于等于'*'
//这两种虽不满足中间的优先级大于等于前后,但实际上可以转化为从左到右的运算,所以为特殊情况
if((minLevel==1 && after==2 && before<=1)
|| (minLevel==3 && after==4 && before<=3)){
s[i] = s[stack.top()] = 0;
}
stack.pop();
}
}
//输出结果
cout<<s;
return 0;
}