LeetCode 224, 227, 772. Basic Calculator I+II+III
Basic Calculator
由于只需要实现加减和括号,除了括号不需要考虑运算的优先级,所以可以直接one pass做。
思路是将 a-b 等价为 a+(-b),这样所有的运算都是加法,而负号只要乘以后面的数即可。
建立一个stack,遇到左括号时,压栈迄今为止的和以及括号前的符号。遇到对应右括号时,括号内已经计算完毕,这时我们将括号内计算得到的sum*栈顶的符号,再加上栈内前面部分的和即可。
class Solution { public: int calculate(string s) { // a-b <=> a+(-b) int res=0, sign=1; stack<int> st; for (int i=0;i<s.size();++i){ char ch=s[i]; if (isdigit(ch)){ int num=0; while (i<s.size() && isdigit(s[i])){ num = num*10 + (s[i++]-'0'); } --i; res += sign*num; }else if (ch=='+' || ch=='-'){ sign = ch=='+'?1:-1; }else if (ch=='('){ st.push(res); st.push(sign); res = 0; sign = 1; }else if (ch==')'){ res *= st.top(); st.pop(); res += st.top(); st.pop(); } } return res; } };
Basic Calculator II
四则运算没有括号,有空格。四则运算就算有括号,用两个stack,其中opstack保证优先级严格单增即可。
discuss 里有很多不用stack的方法,记录之前的符号,读到数字时再根据前面符号处理。个人觉得容易写错,还是标准两个stack比较好,扩展性也更强。
class Solution { public: unordered_map<char,int> pri{{'+',1},{'-',1},{'*',2},{'/',2}}; int calculate(string s) { int res=0; stack<int> numStack; stack<char> opStack; for (int i=0;i<s.size();++i){ char ch=s[i]; if (ch==' ') continue; if (isdigit(ch)){ int num=0; while (i<s.size() && isdigit(s[i])){ num = num*10 + (s[i++]-'0'); } --i; numStack.push(num); }else{ // operand char op=s[i]; while (!opStack.empty() && pri[opStack.top()]>=pri[op]){ calc(numStack,opStack); } opStack.push(op); } } while (!opStack.empty()){ calc(numStack,opStack); } return numStack.top(); } void calc(stack<int> &numStack, stack<char> &opStack){ char op=opStack.top(); opStack.pop(); int num1=numStack.top(); numStack.pop(); int num2=numStack.top(); numStack.pop(); if (op=='+') numStack.push(num2+num1); else if (op=='-') numStack.push(num2-num1); else if (op=='*') numStack.push(num2*num1); else if (op=='/') numStack.push(num2/num1); } };
Basic Calculator III
上一题的followup,存在括号的四则运算。左括号优先级最低,遇到右括号需要一直 calc 直到opStack遇到左括号终止。别的运算比如乘方也可以拓展。
class Solution { public: unordered_map<char,int> pri{{'(',0},{'+',1},{'-',1},{'*',2},{'/',2}}; int calculate(string s) { int res=0; stack<int> numStack; stack<char> opStack; for (int i=0;i<s.size();++i){ char ch=s[i]; if (ch==' ') continue; if (isdigit(ch)){ int num=0; while (i<s.size() && isdigit(s[i])) num = num*10 + (s[i++]-'0'); --i; numStack.push(num); }else { // operand char op=s[i]; if (op=='(') opStack.push(op); else if (op==')'){ while (!opStack.empty() && opStack.top()!='(') calc(numStack,opStack); opStack.pop(); // pop '(' }else{ while (!opStack.empty() && pri[opStack.top()]>=pri[op]) calc(numStack,opStack); opStack.push(op); } } } while (!opStack.empty()){ calc(numStack,opStack); } return numStack.top(); } void calc(stack<int> &numStack, stack<char> &opStack){ char op=opStack.top(); opStack.pop(); int num1=numStack.top(); numStack.pop(); int num2=numStack.top(); numStack.pop(); if (op=='+') numStack.push(num2+num1); else if (op=='-') numStack.push(num2-num1); else if (op=='*') numStack.push(num2*num1); else if (op=='/') numStack.push(num2/num1); } };