Skip to main content

Basic Calculator II


Basic Calculator II: Given a string s which represents an expression, evaluate this expression and return its value.

The integer division should truncate toward zero.

You may assume that the given expression is always valid. All intermediate results will be in the range of [-2^31, 2^31 - 1].

Note: You are not allowed to use any built-in function which evaluates strings as mathematical expressions, such as eval().

Example 1:
Input: s = "3+2*2"
Output: 7

Example 2:
Input: s = " 3/2 "
Output: 1

Example 3:
Input: s = " 3+5 / 2 "
Output: 5

Constraints:
  • 1 <= s.length <= 3 * 10^5
  • s consists of integers and operators ('+', '-', '*', '/') separated by some number of spaces.
  • s represents a valid expression.
  • All the integers in the expression are non-negative integers in the range [0, 2^31 - 1].
  • The answer is guaranteed to fit in a 32-bit integer.

Try this Problem on your own or check similar problems:

  1. Basic Calculator
  2. Expression Add Operators
Solution:
public int calculate(String s) {
int num = 0, lastNum = 0, result = 0;
char operation = '+';

for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (Character.isDigit(c)) {
num = (num * 10) + (c - '0');
}
if (!Character.isDigit(c) && !Character.isWhitespace(c) || i == s.length() - 1) {
if (operation == '+') {
result += lastNum;
lastNum = num;
}
else if (operation == '-') {
result += lastNum;
lastNum = -num;
}
else if (operation == '*') {
lastNum = lastNum * num;
}
else if (operation == '/') {
lastNum = lastNum / num;
}
operation = c;
num = 0;
}
}

return result + lastNum;
}

Time/Space Complexity:
  • Time Complexity: O(n)
  • Space Complexity: O(1)

Explanation:

We first have to ask if we're only given valid expressions (nothing like +*5), since by the problem statement we're, we can proceed. We can use the stack as natural choice when it comes to evaluating expressions like we did in Evaluate Reverse Polish Notation. We have two scenarios either we encounter a sequence of digits, and we build the number each time shifting it by 10 and adding the new digit to the end, or we have an operation (or we traversed the whole string). We keep building the number and we keep track of the last operation (starting with +), when we encounter a new operation, we have to check what our last one was. If it was + or - we just add the number to the stack with correct sign so it can be later added/subtracted to the total sum. If we have * or / we pop the latest number and use it as first operand with the second operand being the number, we just built by traversing the string and we push the result of the operation back in the stack. We record the new operation and reset the num. Finally, we accumulate all the numbers left in the stack and return their sum as the result. Time and space complexity are proportional to the length of input string s.

public int calculate(String s) {
Stack<Integer> stack = new Stack<Integer>();
int num = 0;
char operation = '+';

for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (Character.isDigit(c)) {
num = (num * 10) + (c - '0');
}
if (!Character.isDigit(c) && !Character.isWhitespace(c) || i == s.length() - 1) {
if (operation == '+') {
stack.push(num);
}
else if (operation == '-') {
stack.push(-num);
}
else if (operation == '*') {
stack.push(stack.pop() * num);
}
else if (operation == '/') {
stack.push(stack.pop() / num);
}
operation = c;
num = 0;
}
}

int result = 0;
while (!stack.isEmpty()) {
result += stack.pop();
}
return result;
}

If you think about it we only need stack to hold the last number for us so we can use it as operand and to accumulate the sum of the number in the final stage, so if we accumulate early when we hit + or - operation using a result variable and also keep a reference to the last number lastNum (top of our stack) we can eliminate the need for stack and reduce the space complexity down to O(1).

public int calculate(String s) {
int num = 0, lastNum = 0, result = 0;
char operation = '+';

for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (Character.isDigit(c)) {
num = (num * 10) + (c - '0');
}
if (!Character.isDigit(c) && !Character.isWhitespace(c) || i == s.length() - 1) {
if (operation == '+') {
result += lastNum;
lastNum = num;
}
else if (operation == '-') {
result += lastNum;
lastNum = -num;
}
else if (operation == '*') {
lastNum = lastNum * num;
}
else if (operation == '/') {
lastNum = lastNum / num;
}
operation = c;
num = 0;
}
}

return result + lastNum;
}