解题思路:
1,就是要写个简单的计算器呗
2,先把所有的 space去掉, 实现nonSpace方法;
3,把所有的 operator 和 operands分开,实现简单的 splitToOper 方法;
4,第3步得到的序列,是算数表达式的中缀表达式,计算机不好懂,要转换成逆波兰表达式;实现RPExpression方法
5,有了上述输入序列,这个题就变的跟
Evaluate Reverse Polish Notation 一样简单了
6,除了上述方法,我还写了getPriority, isOperator, strintToInt, doCalculate等辅助方法
下面简述逆波兰表达式的逻辑:
1,前条件:tokens,输入序列
queue<string> s1, 用于存放结果;
stack<string> sOper, 用于存放操作符
sOper.push(‘#’),方便写程序, ‘#’优先级最低
2,不变式:遍历tokens中的每一个字符串elem
a,如果elem是数字,直接加入s.push
b,如果elem是操作符,计算优先级newp;取sOper.top,计算优先级p,
i, 如果newp > p, 则sOper.push(elem);break;
ii,否则,s1.push(sOper.top),sOper.pop。再执行b后半部分,直到出现 i 这个情况
3,结束条件:tokens遍历完,把sOper剩余的elem出了’#’都push到s1
把s1放到vector里面,返回
边界条件:自从push了’#’,就避开了
class Solution {
public:
enum Priority{
BEFORE = 0,
LOW,
HIGH
};
int calculate(string s) {
// delete space
nonSpace(s);
// splite to operators and operands
vector<string> opers;
splitToOper(s, opers);
printf("size of opers %d\n", (int)opers.size());
// convert to RPExpression
vector<string> RPN = RPExpression(opers);
printf("size of RPN %d\n", (int)RPN.size());
//
// stacks
stack<int> operands;
for (auto elem: RPN){
char ch = elem[elem.length() - 1];
if (isOperator(ch)){
doCalculate(ch, operands);
}else{
operands.push(stringToInt(elem));
}
}
printf("size of operands %d\n", (int)operands.size());
return operands.top();
}
vector<string> RPExpression(vector<string> &opers){
queue<string> s1;
stack<string> sOper;
sOper.push(string("#"));
for (auto elem: opers){
char ch = elem[elem.length() - 1];
if (isOperator(ch)){
Priority newp = getPriority(ch);
while(!sOper.empty()){
string op = sOper.top();
Priority lastp = getPriority(op.at(0));
if (newp > lastp){
sOper.push(elem);
break;
}else{
s1.push(op);
sOper.pop();
}
}
}else{
s1.push(elem);
}
}
while(!sOper.empty()){
string op = sOper.top();
sOper.pop();
if (op != "#"){
s1.push(op);
}
}
vector<string > ret;
while(!s1.empty()){
ret.push_back(s1.front());
s1.pop();
}
return ret;
}
void doCalculate(char oper, stack<int> &operands){
int next = operands.top();
operands.pop();
int pre = operands.top();
operands.pop();
int ret;
switch(oper){
case '*':
ret = pre * next;
break;
case '/':
ret = pre / next;
break;
case '+':
ret = pre + next;
break;
case '-':
ret = pre - next;
break;
default:
break;
}
operands.push(ret);
}
int stringToInt(string &s){
return atoi(s.c_str());
}
void splitToOper(string &str, vector<string> &tokens){
auto wordStart = str.begin();
auto it = str.begin();
bool isPreWord = false;
while(it != str.end()){
if (!isdigit(*it)){
if (isPreWord){
isPreWord = false;
string app(wordStart, it);
tokens.push_back(app);
tokens.push_back(string(it, it+1));
}
}else{
if (!isPreWord){
isPreWord = true;
wordStart = it;
}
}
it ++;
}
if (wordStart != it){
tokens.push_back(string(wordStart, it));
}
}
void nonSpace(string &str){
auto it = str.begin();
while(it != str.end()){
if (*it == ' '){
it = str.erase(it);
}else{
it++;
}
}
}
bool isOperator(char ch){
return !isdigit(ch);
}
Priority getPriority(char ch){
Priority ret;
switch(ch){
case '*':
case '/':
ret = HIGH;
break;
case '+':
case '-':
ret = LOW;
break;
case '#':
ret = BEFORE;
break;
default:
printf("invalid operator");
break;
}
return ret;
}
};