Basic Calculator II medium
Problem Statement
Evaluate a given string expression s
that contains numbers and the operators '+', '-', '*', and '/'. The expression should be evaluated according to the standard order of operations (multiplication and division have higher precedence than addition and subtraction). Spaces may appear in the expression.
Example 1
Input: s = "3+2*2" Output: 7 Explanation: This should be evaluated as 3 + (2 * 2) = 7
Example 2
Input: s = " 3/2 " Output: 1 Explanation: This should be evaluated as 3 / 2 = 1 (integer division).
Steps
- Tokenization: Split the input string into tokens (numbers and operators). We'll use a helper function for this.
- Two-Stack Evaluation: Use two stacks: one for numbers (
numStack
) and one for operators (opStack
). - Iterate through Tokens: Process each token:
- If it's a number, push it onto
numStack
. - If it's an operator:
- While
opStack
is not empty and the precedence of the current operator is less than or equal to the precedence of the top operator inopStack
, perform the operation using the top two numbers fromnumStack
. - Push the current operator onto
opStack
.
- While
- If it's a number, push it onto
- Final Calculation: After processing all tokens, perform any remaining operations in
opStack
.
Explanation
The algorithm utilizes the principle of a two-stack evaluation for arithmetic expressions. The precedence of operators is implicitly handled by the while loop in step 3. Multiplication and division are handled before addition and subtraction because they have higher precedence. Integer division is naturally handled by C++'s division operator.
Code
#include <iostream>
#include <string>
#include <stack>
#include <sstream>
using namespace std;
int precedence(char op) {
if (op == '+' || op == '-') return 1;
if (op == '*' || op == '/') return 2;
return 0;
}
int calculate(int a, int b, char op) {
if (op == '+') return a + b;
if (op == '-') return a - b;
if (op == '*') return a * b;
if (op == '/') return a / b; // Integer division
return 0;
}
int calculate(string s) {
stack<int> numStack;
stack<char> opStack;
stringstream ss(s);
string token;
while (ss >> token) {
if (isdigit(token[0])) {
numStack.push(stoi(token));
} else {
while (!opStack.empty() && precedence(token[0]) <= precedence(opStack.top())) {
int b = numStack.top(); numStack.pop();
int a = numStack.top(); numStack.pop();
char op = opStack.top(); opStack.pop();
numStack.push(calculate(a, b, op));
}
opStack.push(token[0]);
}
}
while (!opStack.empty()) {
int b = numStack.top(); numStack.pop();
int a = numStack.top(); numStack.pop();
char op = opStack.top(); opStack.pop();
numStack.push(calculate(a, b, op));
}
return numStack.top();
}
int main() {
string s1 = "3+2*2";
string s2 = " 3/2 ";
string s3 = " 3+5 / 2 "; //test case added
cout << calculate(s1) << endl; // Output: 7
cout << calculate(s2) << endl; // Output: 1
cout << calculate(s3) << endl; //Output: 5
return 0;
}
Complexity
- Time Complexity: O(n), where n is the length of the input string. We iterate through the string once for tokenization and once for evaluation.
- Space Complexity: O(n) in the worst case, due to the stacks which could potentially store all the numbers and operators. In practice, the space used is often much less than n.