Calculator:实现一个计算器,计算只包含数字和加、减、乘、除运算的表达式(在力扣上,运算符两侧可能有空格)。
因为表达式中不包含空格,类似语法分析,可以把表达式拆分为项表达式(Term),项中包含运算符和操作数,然后依次计算即可。
每扫描到一项,如果后一项是乘法或者除法,根据运算符的优先级,应该暂时将这一项应用到临时的计算结果processing中,待乘除法计算完毕后再应用到最终结果result中。书中采用的是将扫描项应用到processing中,根据后一项的运算符决定是否应用到result中。项的默认值为+ 0。
class Solution {
private:
enum class Operator
{
ADD, SUBTRACT, MULTIPLY, DIVIDE
};
struct Term
{
Operator op;
int num;
Term() : op(Operator::ADD), num(0){}
Term(Operator op, string Operand) : op(op), num(stoi(Operand)){}
};
vector<Term> Terms;
void parseTerm(const string &Expression)
{
Operator op = Operator::ADD;
string Operand;
for(auto iter = Expression.begin(); iter != Expression.end(); iter++)
{
if(isspace(*iter));
else if(isdigit(*iter)) Operand.push_back(*iter);
else{
Terms.push_back(Term(op, Operand));
Operand.clear();
switch(*iter)
{
case '+': op = Operator::ADD; break;
case '-': op = Operator::SUBTRACT; break;
case '*': op = Operator::MULTIPLY; break;
case '/': op = Operator::DIVIDE; break;
}
}
}
Terms.push_back(Term(op, Operand));
}
Term apply(const Term &t1, const Term &t2)
{
Term result;
switch(t2.op)
{
case Operator::ADD:
result.num = t1.num + t2.num;
break;
case Operator::SUBTRACT:
result.num = t1.num - t2.num;
break;
case Operator::MULTIPLY:
result.num = t1.num * t2.num;
break;
case Operator::DIVIDE:
result.num = t1.num / t2.num;
break;
}
return result;
}
int compute()
{
Term result;
Term processing;
for(size_t i = 0; i < Terms.size(); i++)
{
const Term ¤t = Terms[i];
const Term &next = i == Terms.size() - 1 ? Term() : Terms[i + 1];
processing = apply(processing, current);
if(next.op == Operator::ADD || next.op == Operator::SUBTRACT){
result = apply(result, processing);
processing = Term();
}
}
return result.num;
}
public:
int calculate(string s) {
parseTerm(s);
return compute();
}
};
还可以借助数据结构中介绍栈时使用的后缀表达式求值的方法。
class Solution {
private:
vector<int> Operands;
vector<char> Operators;
string Operand;
void addOperand()
{
Operands.push_back(stoi(Operand));
Operand.clear();
}
int priority(char op)
{
if(op == '+' || op == '-') return 0;
else return 1;
}
int apply(const int operand1, const int operand2, const char op)
{
if(op == '+') return operand1 + operand2;
else if(op == '-') return operand1 - operand2;
else if(op == '*') return operand1 * operand2;
else return operand1 / operand2;
}
void compute()
{
int operand2 = Operands.back();
Operands.pop_back();
int operand1 = Operands.back();
Operands.pop_back();
Operands.push_back(apply(operand1, operand2, Operators.back()));
Operators.pop_back();
}
public:
int calculate(string s) {
for(char c : s)
{
if(isspace(c));
else if(isdigit(c)) Operand.push_back(c);
else{
addOperand();
while(!Operators.empty() && priority(Operators.back()) >= priority(c)){
compute();
}
Operators.push_back(c);
}
}
addOperand();
while(!Operators.empty()){
compute();
}
return Operands[0];
}
};
也可以递归使用语法树的方法进行计算,不过因为第108个输入太长所以超时了。这种方法的本质是对表达式进行加括号求值。在减号和除号右侧加括号时,需要对被加括号表达式中的加减乘除运算符变号,所以为了方便,代码从最右侧开始加括号,保证了不需要进行变号处理。
class Solution {
public:
int calculate(string s) {
for(size_t i = s.size(); i > 0; i--)
{
if(s[i] == '+' || s[i] == '-'){
int left = calculate(s.substr(0, i));
int right = calculate(s.substr(i + 1));
if(s[i] == '+') return left + right;
else return left - right;
}
}
for(size_t i = s.size(); i > 0; i--)
{
if(s[i] == '*' || s[i] == '/'){
int left = calculate(s.substr(0, i));
int right = calculate(s.substr(i + 1));
if(s[i] == '*') return left * right;
else return left / right;
}
}
return stoi(s);
}
};
本文深入探讨了计算器算法的设计与实现,包括直接应用运算符优先级的计算方法和利用栈处理后缀表达式的策略,以及通过递归语法树进行计算的技术。
4万+

被折叠的 条评论
为什么被折叠?



