表达式求值

题目描述

给定一个包含加号+、减号-、乘号*、左括号(与右括号)的表达式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同号返回正,异号返回负。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值