1.题目
问题描述
小F面临一个编程挑战:实现一个基本的计算器来计算简单的字符串表达式的值。该字符串表达式有效,并可能包含数字(0-9)、运算符+
、-
及括号()
。注意,字符串中不包含空格。除法运算应只保留整数结果。请实现一个解析器计算这些表达式的值,且不使用任何内置的eval
函数。
测试样例
样例1:
输入:expression = "1+1"
输出:
2
样例2:
输入:expression = "3+4*5/(3+2)"
输出:
7
样例3:
输入:expression = "4+2*5-2/1"
输出:
12
样例4:
输入:expression = "(1+(4+5+2)-3)+(6+8)"
输出:
23
样例5:
输入:expression = "2*(5+52)/3+(6+83)"
输出:
40
2.思路
-
初始化两个栈:一个用于存储操作数(数字),另一个用于存储运算符。
-
遍历表达式中的每个字符:
-
如果当前字符是数字,则解析完整的数字并压入操作数栈。
-
如果当前字符是左括号
(
,则直接压入运算符栈。 -
如果当前字符是右括号
)
,则从运算符栈中弹出运算符,并从操作数栈中弹出两个操作数进行计算,直到遇到左括号(
。 -
如果当前字符是运算符(
+
、-
、*
、/
),则比较当前运算符与运算符栈顶运算符的优先级:- 如果当前运算符优先级低于或等于栈顶运算符,则先计算栈顶运算符,并将结果压入操作数栈,然后将当前运算符压入运算符栈。
- 否则,直接将当前运算符压入运算符栈。
-
-
处理完表达式后,如果运算符栈中还有运算符,则依次弹出运算符并进行计算,直到运算符栈为空。
-
最终结果即为操作数栈中的唯一元素。
3.代码
#include <iostream>
#include <string>
#include <stack>
#include <cctype>
using namespace std;
//确定优先级
int precedence(char op) {
if (op == '+' || op == '-') {
return 1;
}else if(op == '*' || op == '/') {
return 2;
}
return 0;
}
//计算
int applyOp(int a, int b, char op){
switch (op) {
case '+' : return a + b;
case '-' : return a - b;
case '*' : return a * b;
case '/' : return a / b;
}
return 0;
}
int solution(const string& tokens) {
stack<int> values; //存放操作数
stack<char> ops; //存放运算符
for (size_t i = 0; i < tokens.length(); ++i) {
// 跳过空格
if (isspace(tokens[i])) {
continue;
}
// 当前字符是数字,则解析完整的数字
if (isdigit(tokens[i])) {
int val = 0;
while (i < tokens.length() && isdigit(tokens[i])) {
val = (val * 10) + (tokens[i] - '0');
++ i;
}
--i; //补偿最后多加一次的递增
values.push(val);
}
// 当前字符是左括号,直接压入运算符栈
else if (tokens[i] == '(') {
ops.push(tokens[i]);
}
// 当前字符是右括号,处理栈中的运算符直到遇到左括号
else if (tokens[i] == ')') {
while (!ops.empty() && ops.top() != '(') {
int val2 = values.top();
values.pop();
int val1 = values.top();
values.pop();
char op = ops.top();
ops.pop();
values.push(applyOp(val1, val2, op));
}
// 弹出左括号
if (!ops.empty()) {
ops.pop();
}
}
// 当前字符是运算符
else {
while (!ops.empty() && precedence(ops.top()) >= precedence(tokens[i])) {
int val2 = values.top();
values.pop();
int val1 = values.top();
values.pop();
char op = ops.top();
ops.pop();
values.push(applyOp(val1, val2, op));
}
ops.push(tokens[i]);
}
}
// 处理栈中剩余的运算符
while (!ops.empty()) {
int val2 = values.top();
values.pop();
int val1 = values.top();
values.pop();
char op = ops.top();
ops.pop();
values.push(applyOp(val1, val2, op));
}
// 栈中应该只剩下一个值,即表达式的计算结果
return values.top();
}
int main() {
// You can add more test cases here
std::cout << (solution("1+1") == 2) << std::endl;
std::cout << (solution("3+4*5/(3+2)") == 7) << std::endl;
std::cout << (solution("4+2*5-2/1") == 12) << std::endl;
std::cout << (solution("(1+(4+5+2)-3)+(6+8)") == 23) << std::endl;
return 0;
}