题目描述
请写一个整数计算器,支持加减乘三种运算和括号。
示例1
输入:"(2*(3-4))*5"
返回值:-10
要想直接求解中缀表达式的值,需要注意:
1)表达式中运算符的优先级
2)遇到括号的处理
与逆波兰表达式不同,中缀表达式考虑的内容多。对于1),如果先计算该运算符就表示该运算符比其余的运算符高,在树中表现为先计算的子树优先级高于后计算的子树,此时需要考虑子树如何根据运算符的不同调整遍历的顺序,其次,遇到括号了,需要找到两个括号‘()’,之间的表达式,对其求解出具体的值再返回。
针对运算符优先级可以根据数值的不同来区分优先级的不同,数值越高代表优先级越大。
需要准备两个栈,一个栈保存参与运算的数字num,一个保存运算符op。
如果遍历到的是数字,就需要根据字符串来获取完整的数字,此时需要进行进一步的转化,注意代码中 i = j - 1,是由于 跳出循环后循环中的j ++ ,再使用 j 会在原来的 j 基础上加1,因此下一次 i 的位置是j-1 。
如果遍历到的是括号,遇到左括号 ( 压入op栈中,遇到右括号 ) 就需要计算括号间的内容,特殊情况是多重括号嵌套问题,由于遇到右括号时就会删除掉一个左括号。
如果遍历到的是运算符就需要看当前运算符的优先级有无op栈顶运算符优先级高,如果有先计算参与op栈顶元素符的结果,那么就需要将num栈的两个数字弹出,并做计算,将最终计算的结果压回栈中,然后再将该运算符压入op栈中。
最后由于计算完成后只是得到最后根节点运算符的左右两个数字,还未进行计算,因此需要再调用一下计算值的函数。
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 返回表达式的值
* @param s string字符串 待计算的表达式
* @return int整型
*/
stack<int> num;
stack<char> op;
void eval()
{
auto b = num.top(); num.pop();
auto a = num.top(); num.pop();
auto c = op.top(); op.pop();
int x;
if (c == '+') x = a + b;
else if (c == '-') x = a - b;
else if (c == '*') x = a * b;
else x = a / b;
num.push(x);
}
unordered_map<char, int> pr{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
int solve(string str) {
// write code here
for (int i = 0; i < str.size(); i ++ )
{
auto c = str[i];
if (isdigit(c))
{
int x = 0, j = i;
while (j < str.size() && isdigit(str[j]))
x = x * 10 + str[j ++ ] - '0';
i = j - 1;
num.push(x);
}
else if (c == '(') op.push(c);
else if (c == ')')
{
while (op.top() != '(') eval();
op.pop();
}
else
{
while (op.size() && pr[op.top()] >= pr[c]) eval();
op.push(c);
}
}
while (op.size()) eval();
return num.top();
}
};
LeetCode 227 基本计算器 II
与上面一道题不一样的是,该题目的输入有"2147483647" ,因此需要将上述记录数字值x 转化为long long 类型。
class Solution {
public:
stack<int> num,op;
void eval()
{
int b=num.top();num.pop();
int a=num.top();num.pop();
char r= op.top();op.pop();
int s=0;
if(r=='+') s=a+b;
else if(r=='-') s=a-b;
else if(r=='*') s=a*b;
else if(r=='/') s=a/b;
num.push(s);
}
unordered_map<char,int> pr{{'+',1},{'-',1},{'/',2},{'*',2}};
int calculate(string s) {
for(int i=0;i<s.size();i++)
{
char c = s[i];
if(c==' ') continue;
if(isdigit(c))
{
long long x=0,j=i;
while(isdigit(s[j])) x=x*10+s[j++]-'0';
num.push(x);
i=j-1;
}
else
{
while(op.size()&&pr[op.top()]>=pr[c]) eval();
op.push(c);
}
}
while(op.size()) eval();
return num.top();
}
};
224. 基本计算器
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
示例 1:
输入:s = “1 + 1”
输出:2
示例 2:
输入:s = " 2-1 + 2 "
输出:3
示例 3:
输入:s = “(1+(4+5+2)-3)+(6+8)”
输出:23
提示:
1 <= s.length <= 3 * 105
s 由数字、’+’、’-’、’(’、’)’、和 ’ ’ 组成
s 表示一个有效的表达式
会出现样例:-2+1,上述两个题目没有这种式子,且上述的模板每次计算需要使用两个数字,因此对于本题目来讲,上述模板需要改动,也就是在式子前面判断开头位置是否是以 减号 开头的,以减号开头的话就在减号前面插入0,注意插入之后字符串长度发生了变化,因此需要重新求解一遍 n。
class Solution {
public:
stack<int> op,nums;
void eval()
{
int b=nums.top();nums.pop();
int a=nums.top();nums.pop();
char r=op.top();op.pop();
int res=0;
if(r=='+') res=a+b;
else if(r=='-') res=a-b;
else if(r=='*') res=a*b;
else if(r=='/') res=a/b;
nums.push(res);
}
unordered_map<char,int> pr{{'+',1},{'-',1},{'*',2},{'/',2}};
int calculate(string s) {
int n=s.size();
int k=0;
while(k<n-1 && s[k]==' ') k++;
if(s[k]=='-') s.insert(k,"0");
n=s.size();
for(int i=0;i<n;i++)
{
char c=s[i];
if(isdigit(c))
{
int j=i;
long long x=0;
while(j<n && isdigit(s[j])) x=x*10+s[j++]-'0';
i=j-1;
nums.push(x);
}
else if(c==' ') continue;
else if(c=='(') op.push(c);
else if(c==')')
{
while(op.top()!='(') eval();
op.pop();
}
else
{
while(op.size() && pr[op.top()]>=pr[c]) eval();
op.push(c);
}
}
while(op.size()) eval();
return nums.top();
}
};