📅  最后修改于: 2023-12-03 15:28:38.271000             🧑  作者: Mango
这道题目来自 Gate CS 2019 的第 64 题,涉及到对于运算符和优先级的理解。题目如下:
给定一个算术表达式的字符串,其中运算符仅包括加号和乘号,数字可以是单个数字或多位数字。例如,表达式 1 + 2 + 3 和 2 * 3 * 4 是有效的表达式,而表达式 1 + 2 * 3 和 2 * 3 + 4 * 5 + 是无效的表达式。需要通过对运算符的分析来计算出表达式的结果。
你需要实现一个函数,接受字符数组作为输入,计算并返回表达式的结果,若输入的表达式不符合规则,则应该返回 -1。
函数原型为:int evaluate(char *expression);
例如,对于字符串 "2 * 3 + 4",你的程序应该返回 10,因为这个表达式等价于 2 * (3 + 4) = 14。
本题思路比较简单,可以通过使用栈来实现。从左至右扫描表达式字符串,如果是数字,就将其压入栈中;如果是运算符,就弹出栈顶的两个数字,并按照运算符的优先级进行计算,将结果重新压入栈中。
在本题中,加法和乘法的优先级不同,因此需要对其进行判断。如果当前的运算符是乘法,就需要再弹出一个数字,并将两个数字乘起来。最后,当整个字符串扫描完毕后,栈中仅剩下一个数字,即为表达式的值。
如果在扫描过程中发现输入的表达式不符合规则,则应该返回 -1。
下面是使用栈实现的 C++ 代码:
#include <iostream>
#include <stack>
using namespace std;
// 判断一个字符是否为数字
bool isNumericChar(char c) {
return (c >= '0' && c <= '9') ? true : false;
}
// 将字符数组形式的数字转换为整型数字
int charToNum(char c) {
return c - '0';
}
// 计算表达式的值
int evaluate(char *expression) {
stack<int> nums; // 用于存储数字的栈
stack<char> ops; // 用于存储运算符的栈
for (int i = 0; expression[i]; i++) {
if (expression[i] == ' ') {
continue; // 忽略空格
}
else if (expression[i] == '(') {
ops.push(expression[i]);
}
else if (isNumericChar(expression[i])) {
// 如果是数字,则将连续的数字组成一个整数,然后压入数字栈中
int num = 0;
while (isNumericChar(expression[i])) {
num = num * 10 + charToNum(expression[i]);
i++;
}
i--; // 因为循环结束后 i 多余了 1
nums.push(num);
}
else if (expression[i] == '+' || expression[i] == '*') {
// 如果是运算符,则将栈顶的两个数字弹出并进行运算,
// 然后将结果压回数字栈中,最后将当前运算符压回运算符栈中
while (!ops.empty() && ops.top() != '(' &&
((expression[i] == '*' && ops.top() == '+') || (expression[i] == '*' && ops.top() == '*'))) {
int num2 = nums.top();
nums.pop();
int num1 = nums.top();
nums.pop();
char op = ops.top();
ops.pop();
if (op == '+') {
nums.push(num1 + num2);
}
else if (op == '*') {
nums.push(num1 * num2);
}
}
ops.push(expression[i]);
}
else if (expression[i] == ')') {
// 如果是右括号,则将栈顶的两个数字弹出并进行运算,
// 然后将结果压回数字栈中,直到遇到了左括号为止,
// 最后将左右括号都弹出
while (!ops.empty() && ops.top() != '(') {
int num2 = nums.top();
nums.pop();
int num1 = nums.top();
nums.pop();
char op = ops.top();
ops.pop();
if (op == '+') {
nums.push(num1 + num2);
}
else if (op == '*') {
nums.push(num1 * num2);
}
}
ops.pop(); // 弹出左括号
}
else {
// 如果输入的表达式不符合规则,则返回 -1
return -1;
}
}
// 如果这个时候操作符栈不为空,还需要执行一遍计算
while (!ops.empty()) {
int num2 = nums.top();
nums.pop();
int num1 = nums.top();
nums.pop();
char op = ops.top();
ops.pop();
if (op == '+') {
nums.push(num1 + num2);
}
else if (op == '*') {
nums.push(num1 * num2);
}
}
// 最后栈中剩下的唯一一个数字即为表达式的值
return nums.top();
}
注:本代码采用了算法竞赛入门经典(第 2 版)中的实现方式。
在解决函数实现的问题时,需要注意细节,特别是在输入的表达式出现不符合规则的情况下,需要返回 -1。这也是本题比较难的地方之一。当然,借助栈这种数据结构,结合运算符的优先级,还是比较好实现的,特别是当我们选择较为合适的实现方式时,算法的时间复杂度可以做到 O(n)。