Basic Calculator hard
Problem Statement
Evaluate a string expression representing a basic calculator. The expression contains digits, +
, -
, (
, and )
. You can assume the given expression is always valid.
Example 1
Input: s = "1 + 1" Output: 2
Example 2
Input: s = " 2-1 + 2 " Output: 3
Steps
This problem requires handling operator precedence and parentheses. We'll use a stack-based approach to solve it:
-
Initialization: Create two stacks: one for numbers (
numStack
) and one for operators (opStack
). We'll also need a variablesign
to track the current sign (+1 or -1). -
Iteration: Iterate through the input string
s
:- Whitespace: Ignore whitespace characters.
- Digit: Read consecutive digits to form a number and push it onto
numStack
after multiplying by the currentsign
. - '+' or '-': Push the current number (with the appropriate sign) onto
numStack
, update thesign
, and continue. - '(': Push the current
sign
and the current value ofopStack
onto their respective stacks and reset thesign
to +1. This handles nested parentheses. - ')': While the top of
opStack
is not '(', pop operators and operands, perform calculations and push the result ontonumStack
. Then, pop the previoussign
andopStack
value, restoring the context.
-
Final Calculation: After processing the entire string, perform any remaining operations on the stacks.
Explanation
The stack-based approach simulates the order of operations. The opStack
stores pending operations, and parentheses are handled by pushing and popping the state of the stack, ensuring correct precedence. The sign
variable efficiently handles the positive or negative sign before each number.
Code
function calculate(s: string): number {
const numStack: number[] = [];
const opStack: string[] = [];
let sign: number = 1;
let num: number = 0;
for (let i = 0; i < s.length; i++) {
const char = s[i];
if (/\d/.test(char)) {
num = num * 10 + parseInt(char);
}
if (!/\d/.test(char) && char !== ' ' || i === s.length -1) {
numStack.push(num * sign);
num = 0;
sign = 1;
}
if (char === '+') {
} else if (char === '-') {
sign = -1;
} else if (char === '(') {
opStack.push(String(sign));
opStack.push('(');
sign = 1;
} else if (char === ')') {
while (opStack.length > 0 && opStack[opStack.length - 1] !== '(') {
const op = opStack.pop();
const num2 = numStack.pop();
const num1 = numStack.pop();
numStack.push(op === '+' ? num1 + num2 : num1 - num2);
}
opStack.pop(); // Pop the '('
if(opStack.length > 0){
sign = parseInt(opStack.pop())
}
}
}
return numStack.reduce((sum, num) => sum + num, 0);
}
Complexity
- Time Complexity: O(n), where n is the length of the input string. We iterate through the string once.
- Space Complexity: O(n) in the worst case, as the stacks can grow up to the size of the input string (e.g., deeply nested parentheses). In the average case, it will be less than O(n).