题目描述
给定一个包含加号+
、减号-
、乘号*
、左括号(
与右括号)
的表达式s,请求出表达式s的计算结果。
保证s是一个合法的算术表达式,且出现的加号、减号、乘号都是二元运算符(加号、减号、乘号的左右两边都是数字或者是一对括号包围的合法算术表达式),也就是说不会出现形如-3+4
或者2+(+3+5)
的表达式。
输入格式
输入的第一行,包括一个字符串,表示算术表达式s。
输出格式
输出一行,包括一个整数,表示s的计算结果。
样例输入 #1
3+5*6-2
样例输出 #1
31
样例输入 #2
(8-2)*4+5*(2-1)
样例输出 #2
29
样例输入 #3
((3-2)*2+3)*2+(6-8)*(2+1)
样例输出 #3
4
样例输入 #4
4*313-(((323+2217)*513)-8)
样例输出 #4
-1301760
提示
本题共25个测试点。
测试点1∼2满足:∣s∣≤10,s不含括号,并且s只出现一个算术运算符(加号、减号、乘号);
测试点3∼4满足:∣s∣≤100,s中不会出现括号、减号与乘号,答案不超过int范围;
测试点5∼6满足:∣s∣≤100,s中不会出现括号与乘号,答案不超过int范围;
测试点7∼8满足:∣s∣≤100,s中不会出现括号,答案不超过int范围;
测试点9∼10满足:∣s∣≤100,s中最多只出现一对括号,答案不超过int范围;
测试点11∼12满足:∣s∣≤700,s中不会出现括号、减号与乘号;
测试点13∼14满足:∣s∣≤700,s中不会出现括号与乘号;
测试点15∼16满足:∣s∣≤700,𝑠s中不会出现括号;
测试点17∼19满足:∣s∣≤700,s中最多只出现一对括号;
测试点20∼22满足:∣s∣≤700,s中不存在嵌套的括号;
对于所有测试点均满足:∣s∣≤700,s是一个合法的算术表达式,且出现的加号、减号、乘号都是二元运算符。s中不含有空格或其它多余的字符。
#include <bits/stdc++.h>
using namespace std;
struct hgh
{
vector<int>v;
bool sign;
};
struct node
{
hgh sum;
hgh add;
};
stack<node>st;
void P(hgh a)
{
if(a.v.size()==1&&a.v[0]==0)
{
cout<<0;
return;
}
if(!a.sign)
cout<<"-";
for(int i=a.v.size()-1;i>=0;i--)
cout<<a.v[i];
}
bool B(vector<int>a,vector<int>b)
{
if(a.size()!=b.size())
return a.size()>b.size();
for(int i=a.size()-1;i>=0;i--)
if(a[i]!=b[i])
return a[i]>b[i];
return false;
}
hgh S(hgh a,hgh b)
{
int n=a.v.size(),m=b.v.size();
vector<int>sm(max(n,m)+1);
for(int i=0;i<n;i++)
sm[i]=a.v[i];
for(int i=0;i<m;i++)
sm[i]+=b.v[i];
int c=0;
for(int i=0;i<max(n,m)+1;i++)
{
sm[i]+=c;
c=sm[i]/10;
sm[i]%=10;
}
while(sm.size()>1&&sm[sm.size()-1]==0)
sm.pop_back();
return {sm,a.sign};
}
hgh D(hgh a,hgh b)
{
int n=a.v.size(),m=b.v.size();
vector<int>dff(n,0);
for(int i=0;i<n;i++)
dff[i]=a.v[i];
for(int i=0;i<m;i++)
dff[i]-=b.v[i];
for(int i=0;i<n;i++)
{
while(dff[i]<0)
{
dff[i+1]--;
dff[i]+=10;
}
}
while(dff.size()>1&&dff[dff.size()-1]==0)
dff.pop_back();
return {dff,a.sign};
}
hgh A(hgh a,hgh b)
{
if(!B(a.v,b.v))
swap(a,b);
if(a.sign==b.sign)
return S(a,b);
return D(a,b);
}
hgh M(hgh a, hgh b)
{
int n=a.v.size(),m=b.v.size();
vector<int>prd(n+m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
prd[i+j]+=a.v[i]*b.v[j];
int c=0;
for(int i=0;i<n+m;i++)
{
prd[i]+=c;
c=prd[i]/10;
prd[i]%=10;
}
while(prd.size()>1&&prd[prd.size()-1]==0)
prd.pop_back();
return {prd,a.sign==b.sign};
}
int main()
{
string s;
cin>>s;
int n=s.size();
st.push({{{0},true},{{1},true}});
for(int i=0;i<n;i++)
{
node &nd=st.top();
char c=s[i];
if(c>='0'&&c<='9')
{
vector<int>mlt;
mlt.push_back(c-'0');
while(i+1<n&&s[i+1]>='0'&&s[i+1]<='9')
{
i++;
mlt.push_back(s[i]-'0');
}
reverse(mlt.begin(),mlt.end());
nd.add=M(nd.add,{mlt,true});
}
else if(c=='+'||c=='-')
{
nd.sum=A(nd.sum,nd.add);
nd.add={{1},c=='+'};
}
else if(c=='(')
st.push({{{0},true},{{1},true}});
else if(c==')')
{
auto sum=A(nd.sum,nd.add);
st.pop();
node &nod=st.top();
nod.add=M(nod.add,sum);
}
}
node &nd=st.top();
nd.sum=A(nd.sum,nd.add);
P(nd.sum);
return 0;
}
前方高能——此题刷新了我的代码长度记录!
主题思路:中缀表达式+高精度。本blog中会分开讲解,具体结合较为简单(拆函数即可),见代码。
中缀表达式:
简介:这道题的中缀表达式涉及到数、+、-、*、(和),由于数会超long long,所以计算时需使用高精度。首先输入字符串,接着遍历处理,每种情况做不同的事情。定义一个node,里面有一个sum和一个add,类型是hgh(high,高精度struct,见高精度)。计算时用一个node类型的stack,遇到括号就把当前结果先存起来push一个新的,括回时pop出来加回去。我们把一串乘积或一个数叫做一个加数(add),最终将所有加数加起来就是答案。
初始化:输入字符串s,stack里push一个node,sum置成正0,add置成正1,开始遍历字符串。
数:由于种种原因(见高精度),数需要存成vector。数不一定是一位数,所以当遇到一个数字时,要定义一个vector并进行while循环,把后面的一串数字都push_back到这个vector里。再由于高精度中的原因,最后要reverse下,达到个位在最左边,高位在最右边。接着,我们要把这个vector乘到add里。add初始化为正1。
+/-:sum要+=add,因为如简介所说,这个加数是时候加到sum里了。注意此时加的符号取决于上一次,每次遇到+/-,将add清为1,是+就是正,反之是-,下次就使用这次的符号。
*:不用考虑,因为在数中自动乘上了。
(:stack push一个新的,sum置成正0,add置成正1。
):先把刚刚的add加到sum中,记录sum,stack pop一下(即来到括号外),将当前这一层(括号外)的add*=刚才的sum!重点!这是括号内外联系!
结尾:再把sum+=add(最后一次没符号也得加),输出sum。
高精度:
简介:每个数是一个hgh类型,即一个vector的v代表数值(倒序),和一个bool的sign代表正负(true正)。本题中的高精度主要用在函数中,我也就只讲函数,连接看代码。
P函数:print输出,由于v是倒序存的,也要再倒序输出。先判断是否为0,是就输出0直接return。否则如果为负数输出‘-’,剩下就是倒序输出v即可。
B函数:big判断绝对值大小,先看位数,若位数不同按位数大为大;若位数相同从高到低逐位比较,注意由于是倒序存储,高位在右边,要从后往前比较。
A函数:add加,A函数比较短是因为把他拆成了S、D两种情况。首先把加数a,b swap成a的绝对值更大,方便计算。如果ab符号相同,那么结果绝对值是ab绝对值之和,放进S函数计算;反之说明结果绝对值是ab绝对值之差,放进D函数计算。
S函数:sum加,先定义n,m代表两数长度,接着定义int类型vector sm(sum)算和。sm初始化长度为max(n,m)+1,这是和的最大长度。
(1)两遍循环赋值,使sm[i]等于a.v[i](如果有)+b.v[i](如果有)。
(2)处理进位,定义c=0(进位),遍历sm,sm[i]先+=c,c更新为sm[i]/10(即需要进的位数),最后位都进完了,sm[i]就可以%=10了。
(3)消掉前导0,只要长度>1(省的把0变成啥也没有)且最高位是0,就pop_back去掉这个0。
(4)return一个hgh类型,v是我们刚算出来的和sm,sign跟着a(b也一样)就行。
D函数:difference减,先定义n,m代表两数长度,接着定义int类型vector dff(difference)算差。dff初始化长度为max(n,m),这是差的最大长度。
(1)两遍循环赋值,使sm[i]等于a.v[i](如果有)-b.v[i](如果有)。
(2)处理借位,dff[i]可能是负数,所以while dff[i]是负数,i+1位--,i位+=10(借位)。
(3)消掉前导0,只要长度>1且最高位是0,就pop_back去掉这个0。
(4)return一个hgh类型,v是我们刚算出来的和dff,sign跟着a(a绝对值>b绝对值,跟a同号)就行。
M函数:multiple乘,先定义n,m代表两数长度,接着定义int类型vector prd(product)算积。prd初始化长度为n+m,这是积的最大长度。
(1)两层循环赋值,i从0~n-1,j从0~m-1,prd[i+j]加等于adff.v[i]和b.v[j]的积。
(2)处理进位,定义c=0(进位),遍历prd,sprd[i]先+=c,c更新为prd[i]/10(即需要进的位数),最后prd[i]%=10。
(3)消掉前导0,只要长度>1且最高位是0,就pop_back去掉这个0。
(4)return一个hgh类型,v是我们刚算出来的和prd,如果ab同号返回正,异号返回负。