題目:
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();
}
};