题目:
Implement a basic calculator to evaluate a simple expression string.
The expression string contains only non-negative integers, +, -, *, / operators and empty spaces . The integer division should truncate toward zero.
思路:
设置两个栈nums_stack和opt_stack。nums_stack存放数字,opt_stack存放运算符。如果当前运算符比前一个运算符的优先级更大,则将当前运算符压入opt_stack中;否则,先对前一个运算符进行计算,从nums_stack取出两个数字,计算结果再压入nums_stack中。也就是说,opt_stack从栈底到栈顶存放的运算符的优先级是从低到高的(也不会存放优先级相等的运算符)。最后,如果opt_stack不为空,逐个弹出并运算就好了。
后来我发现,其实nums_stack最多也就3个元素,opt_stack最多也就2个元素,所以不用麻烦STL了,自己用小小的数组设计了一个固定容量的stack,效率稍稍有所提升。
代码实现:
优化之前:
class Solution {
public:
bool isOpt(char c){
if (c == '+' || c == '-' || c == '*' || c == '/'){
return true;
}
return false;
}
bool isNum(char c){
if (c >= '0' && c <= '9'){
return true;
}
return false;
}
int getNumEnd(string &s, int begin){
while (begin < s.size() && isNum(s[begin])){
++begin;
}
return begin-1;
}
int calc(int num1, int num2, char opt){
int ret;
switch (opt){
case '+':
ret = num1 + num2;
break;
case '-':
ret = num1 - num2;
break;
case '*':
ret = num1 * num2;
break;
case '/':
ret = num1 / num2;
break;
}
return ret;
}
int calculate(string s) {
stack<int> nums_stack;
stack<char> opt_stack;
unordered_map<char, int> priority;
priority['+'] = 0;
priority['-'] = 0;
priority['*'] = 1;
priority['/'] = 1;
for (int i = 0; i < s.size(); ++i){
if (isOpt(s[i])){
if (!opt_stack.empty()){
if (priority[s[i]] > priority[opt_stack.top()]){
opt_stack.push(s[i]);
}else{
int num2 = nums_stack.top(); nums_stack.pop();
int num1 = nums_stack.top(); nums_stack.pop();
char opt = opt_stack.top(); opt_stack.pop();
nums_stack.push(calc(num1, num2, opt));
--i;
}
}else{
opt_stack.push(s[i]);
}
}else if (isNum(s[i])){
int num_end = getNumEnd(s, i);
nums_stack.push(stoi(s.substr(i,num_end-i+1)));
i = num_end;
}
}
while (!opt_stack.empty()){
int num2 = nums_stack.top(); nums_stack.pop();
int num1 = nums_stack.top(); nums_stack.pop();
char opt = opt_stack.top(); opt_stack.pop();
nums_stack.push(calc(num1, num2, opt));
}
return nums_stack.top();
}
};
优化之后:
template<typename T>
class my_stack {
private:
T* vec;
int i;
public:
my_stack(int size) :vec(new T[size]), i(-1) {
}
void push(T e){
vec[++i] = e;
}
void pop(){
--i;
}
T top(){
return vec[i];
}
bool empty(){
return i <= -1;
}
};
class Solution {
public:
bool isOpt(char c){
if (c == '+' || c == '-' || c == '*' || c == '/'){
return true;
}
return false;
}
bool isNum(char c){
if (c >= '0' && c <= '9'){
return true;
}
return false;
}
int getNumEnd(string &s, int begin){
while (begin < s.size() && isNum(s[begin])){
++begin;
}
return begin-1;
}
int calc(int num1, int num2, char opt){
int ret;
switch (opt){
case '+':
ret = num1 + num2;
break;
case '-':
ret = num1 - num2;
break;
case '*':
ret = num1 * num2;
break;
case '/':
ret = num1 / num2;
break;
}
return ret;
}
int calculate(string s) {
my_stack<int> nums_stack(3);
my_stack<char> opt_stack(2);
unordered_map<char, int> priority;
priority['+'] = 0;
priority['-'] = 0;
priority['*'] = 1;
priority['/'] = 1;
for (int i = 0; i < s.size(); ++i){
if (isOpt(s[i])){
if (!opt_stack.empty()){
if (priority[s[i]] > priority[opt_stack.top()]){
opt_stack.push(s[i]);
}else{
int num2 = nums_stack.top(); nums_stack.pop();
int num1 = nums_stack.top(); nums_stack.pop();
char opt = opt_stack.top(); opt_stack.pop();
nums_stack.push(calc(num1, num2, opt));
--i;
}
}else{
opt_stack.push(s[i]);
}
}else if (isNum(s[i])){
int num_end = getNumEnd(s, i);
nums_stack.push(stoi(s.substr(i,num_end-i+1)));
i = num_end;
}
}
while (!opt_stack.empty()){
int num2 = nums_stack.top(); nums_stack.pop();
int num1 = nums_stack.top(); nums_stack.pop();
char opt = opt_stack.top(); opt_stack.pop();
nums_stack.push(calc(num1, num2, opt));
}
return nums_stack.top();
}
};