本博客介绍leetcode上的一道不难,但是比较经典的算法题。
题目如下:
Implement a basic calculator to evaluate a simple expression string.
The expression string may contain open
(
and closing parentheses)
, the plus+
or minus sign-
, non-negative integers and empty spaces.
You may assume that the given expression is always valid.
Some examples:
也可以直接参考 https://leetcode.com/problems/basic-calculator/
这是简单的加减计算运算题,一个直观的思路是运用栈,以及用后缀表达式求值。实现这一种算法,需要构造两个栈,分别是运算符栈和数字栈,然后将输入的中序表达式在转化为后续表达式的过程中求值。
考虑到这道题目的特殊性,运算符只有加减和括号,我们可以转化加减运算符为(±1),这样可以省略计算时的判断语句,而直接将转化后的运算符数作为被加(减)数的系数
这是我的代码
int calculate(string s) { s.push_back('#'); //防止栈溢出 stack<int>num; //数字栈 stack<int>oper; //运算符栈 for(int i=0; i<s.length()-1;++i) { if(isdigit(s[i])) //判断数字,压入数字栈 { int temp = s[i]-'0'; while(++i && isdigit(s[i])) { temp = temp * 10 + s[i] - '0'; } num.push(temp); } switch (s[i]){ case '(': //'('直接压入栈,其代表数为0 oper.push(0); break; case '+': case '-': if(!oper.empty() && oper.top() != 0) //栈中有加减运算符,则先弹出,再压入现在的运算符 { int num1 = num.top(); num.pop(); int num2 = num.top(); num.pop(); num.push(num2 + num1 * oper.top()); oper.pop(); } if(s[i] == '-') oper.push(-1); else oper.push(1); break; case ')': //为')',则一直弹出栈至弹出第一个'(' if(oper.top() == 0) oper.pop(); else { int num1 = num.top(); num.pop(); int num2 = num.top(); num.pop(); num.push(num2 + num1 * oper.top()); oper.pop(); oper.pop(); } break; case '#': break; } } if(oper.empty()) return num.top(); else { int num1 = num.top(); num.pop(); int num2 = num.top(); num.pop(); return (num2 + num1 * oper.top()); } }
其实这个算法的效率并不是很高,原因在于,每个数字都要压栈、退栈,每个操作符(除了')')也同样如此。
下面这个算法是讨论区上面的比较优秀的算法,其亮点是
- 用独立的变量存储上次的数字和加减运算符,在n次连续加减运算时省略了分别n-1次出入栈;
- 遇到'(',只压入前面的加减运算符,默认为加法。
class Solution { public: int calculate(string s) { stack <int> nums, ops; int num = 0; int rst = 0; int sign = 1; for (char c : s) { if (isdigit(c)) { num = num * 10 + c - '0'; } else { rst += sign * num; num = 0; if (c == '+') sign = 1; if (c == '-') sign = -1; if (c == '(') { nums.push(rst); ops.push(sign); rst = 0; sign = 1; } if (c == ')' && ops.size()) { rst = ops.top() * rst + nums.top(); ops.pop(); nums.pop(); } } } rst += sign * num; return rst; } };
也可以参考https://leetcode.com/discuss/53921/16-ms-solution-in-c-with-stacks