Template for basic calculator problems
2025-03-23
There are several Leetcode problems themed around basic calculator. These problems involve evaluating mathematical expressions represented as strings:
Given a valid math expression as a string, return its corresponding value.
Here are the main problems in this series:
-
- Supports:
+,-,(,)
- Supports:
-
- Supports:
+,-,*,/
- Supports:
-
- Supports:
+,-,*,/,(,)
- Supports:
A generic solution template with O(n) time and space complexity for this series is introduced in this discussion post. We reorganize and present the approach in a more intuitive and structured way.
Content
Variable definition
l1: Left operand for addition/subtractiono1: Operator for addition/subtraction (1for+,-1for-)l2: Left operand for multiplication/divisiono2: Operator for multiplication/division (1for*,-1for/)
We categorize operations as follows:
-
Level-1 operations (lower precedence):
+,-
→ Represented byo1(+→1,-→-1) -
Level-2 operations (higher precedence):
*,/
→ Represented byo2(*→1,/→-1)
Default initialization:
int l1 = 0, o1 = 1;
int l2 = 1, o2 = 1;
This setup allows any number num to be represented as:
num = l1 + o1 * (l2 * num)
with initial values l1 = 0, o1 = 1, l2 = 1
Actions
Case 1. We just parsed a number num
Because * and / (i.e. o2) are of higher precedence than + and -, we evaluate the level-2 operation immediately upon parsing a number.
l2 = (o2 == 1 ? l2 * num : l2 / num);
By doing this, we ensure that multiplication and division are resolved before being combined with addition or subtraction at the higher level. As the expression can always be viewed as:
l1 + o1 * (l2 [* or /] num)
Case 2. We just parsed an opening bracket (
An opening bracket signals the start of a new sub-expression. To correctly evaluate it in the context of the outer expression, we must:
-
Save the current state
Push the current values ofl1,o1,l2, ando2onto a stack. This allows us to return to the outer expression once the sub-expression is evaluated. -
Reset all variables
Initialize for evaluating the expression inside the brackets
Example:
For the expression 2 + 3 * (4 - 1), when we encounter the (, we:
- Pause the outer computation of
2 + 3 *by saving the current state (l1 = 2,o1 = 1,l2 = 3,o2 = 1) onto the stack. - Reset the variables to start fresh and evaluate the sub-expression
4 - 1.
Once the sub-expression is fully evaluated (resulting in 3), it will be merged back into the outer expression as: 2 + 3 * 3 = 11
Case 3. We just parsed a closing bracket )
We want to
-
compute the result of the expression inside the brackets
we do
int num = l1 + o1 * l2;where
-
l1holds the sum of all the prior+/-chunks -
l2is the current multiplication/division results -
o1is the current +/- operation
-
-
restore the outer state
- we pop the saved values from the stack
-
merge the inner result with the outer part
-
we do
l2 = (o2 == 1 ? l2 * num : l2 / num);
where
-
numis the inner result we just computed -
l2ando2are outer expressions
e.g.
-
3 * (2 + 4) →
l2 = 3, o2 = 1, num = 6→ now:l2 = 3 * 6 = 18 -
12 / (2 + 2) →
l2 = 12, o2 = -1, num = 4→ now:l2 = 12 / 4 = 3
-
Case 4. We just parsed a level-2 operator (* or /)
Simply update o2 to prepare for next operation
o2 = (c == '*') ? 1: -1;
Case 5. We just parsed a level-1 operator (+ or -)
We want to
-
Compute the result of the current term
l1 = l1 + o1 * l2;where
-
l2holds the result of any prior multiplication/division -
o1is the current+or-operator
-
-
Store the newly parsed operator
This operator will be used when the next complete term is merged with
l1 -
Reset level-2 states
We prepare for parsing a new term by resetting the level-2 variables to:
-
Start fresh with a new term:
l2 = 1 -
Prepare for potential multiplication or division:
o2 = 1
-
Code
Template code
Based on LC 772 Basic Calculator III - includes + - * / ( )
int calculate(string s) {
// Level 1: For + or -
int l1 = 0, o1 = 1;
// Level 2: For * or /
int l2 = 1, o2 = 1;
stack<int> stk;
for (int i = 0; i < s.length(); ++i) {
char c = s[i];
if (isdigit(c)) {
int num = c - '0';
while (i + 1 < s.length() && isdigit(s[i + 1])) {
num = num * 10 + (s[++i] - '0');
}
// Apply current multiplication/division operation
l2 = (o2 == 1 ? l2 * num : l2 / num);
} else if (c == '(') {
// Save current state
stk.push(l1); stk.push(o1);
stk.push(l2); stk.push(o2);
// Reset for the new sub-expression (inside the upcoming brackets)
l1 = 0; o1 = 1;
l2 = 1; o2 = 1;
} else if (c == ')') {
// Compute the result of the expression inside the brackets
int num = l1 + o1 * l2;
// Restore the outer state
o2 = stk.top(); stk.pop();
l2 = stk.top(); stk.pop();
o1 = stk.top(); stk.pop();
l1 = stk.top(); stk.pop();
l2 = (o2 == 1 ? l2 * num : l2 / num);
} else if (c == '*' || c == '/') {
o2 = (c == '*' ? 1 : -1);
} else if (c == '+' || c == '-') {
// Apply current term (l2) to result
l1 = l1 + o1 * l2;
// Update sign for next term
o1 = (c == '+' ? 1 : -1);
// Reset level 2 computation
l2 = 1; o2 = 1;
}
}
// Add the last processed value
return l1 + o1 * l2;
}
LC 227 Basic Calculator II - includes + - * /
For LC 227. Basic Calculator II, simply delete the code block of dealing with brackets from the template:
else if (c == '(') { ... }
else if (c == ')') { ... }
LC 224 Basic Calculator - includes + - ( )
Based on the template:
-
Remove the lines associated with
l2,o2 -
Remove the if statement dealing with iterating level-2 operators
else if (c == '*' || c == '/') { ... } -
Because there are only level-1 operators, the temporary sum is always
l1 = l1 + o1 * num;
This is the case for both isdigit(c) and c == ')'
The code becomes
int calculate(string s) {
int l1 = 0, o1 = 1;
stack<int> stk;
for (int i = 0; i < s.length(); ++i) {
char c = s[i];
if (isdigit(c)) {
int num = c - '0';
while (i + 1 < s.length() && isdigit(s[i + 1])) {
num = num * 10 + (s[++i] - '0');
}
l1 = l1 + o1 * num;
} else if (c == '(') {
stk.push(l1); stk.push(o1);
l1 = 0; o1 = 1;
} else if (c == ')') {
int num = l1;
o1 = stk.top(); stk.pop();
l1 = stk.top(); stk.pop();
l1 = l1 + o1 * num;
} else if (c == '+' || c == '-') {
o1 = (c == '+' ? 1 : -1);
}
}
return l1 ;
}