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()
.
For example:
s = "3+2*2"
should return 7
s = " 3/2 "
should return 1
s = " 3+5 / 2 "
should return 5
Write a function to implement this. Consider the constraints:
1 <= s.length <= 3 * 10^5
s
consists of integers and operators ('+', '-', '*', '/')
separated by some number of spaces.s
represents a valid expression.[0, 2^31 - 1]
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach for evaluating a simple expression like '3+2*2' means we don't use any clever tricks. Instead, we explore all possible interpretations of the expression, even the wrong ones, until we find the correct answer. We treat everything like plain text and try every possibility.
Here's how the algorithm would work step-by-step:
def basic_calculator_ii_brute_force(expression):
results = []
current_number = 0
current_result = 0
operation = '+'
def evaluate(number_to_consider, current_operation):
nonlocal current_result
if current_operation == '+':
current_result += number_to_consider
elif current_operation == '-':
current_result -= number_to_consider
elif current_operation == '*':
current_result *= number_to_consider
elif current_operation == '/':
# Integer division as specified in the prompt
current_result = int(current_result / number_to_consider)
for character in expression:
if character.isdigit():
current_number = current_number * 10 + int(character)
elif character in '+-*/':
# Evaluate the previous operation with the current number
evaluate(current_number, operation)
results.append(current_result)
current_number = 0
operation = character
elif character == ' ':
pass
# Evaluate the last operation with the last number
evaluate(current_number, operation)
results.append(current_result)
# Return the last result after all calculations
# This implicitly tries all combinations
return results[-1]
The optimal approach avoids treating multiplication and division the same as addition and subtraction. Instead, we tackle the higher-priority math first, then the rest. This simplifies the calculation to a series of simple additions and subtractions.
Here's how the algorithm would work step-by-step:
def calculate(expression):
current_number = 0
stack_of_numbers = []
last_operation = '+'
for i, character in enumerate(expression):
if character.isdigit():
current_number = (current_number * 10) + int(character)
if character in '+-*/' or i == len(expression) - 1:
# Evaluate high-precedence operations immediately.
if last_operation == '+':
stack_of_numbers.append(current_number)
elif last_operation == '-':
stack_of_numbers.append(-current_number)
elif last_operation == '*':
stack_of_numbers.append(stack_of_numbers.pop() * current_number)
else:
stack_of_numbers.append(int(stack_of_numbers.pop() / current_number))
last_operation = character
current_number = 0
# Sum remaining values in stack now, only additions and subtractions remain.
result = 0
for number in stack_of_numbers:
result += number
return result
Case | How to Handle |
---|---|
Null or empty input string | Return 0 immediately as there is no expression to evaluate. |
Input string with only whitespace | Return 0 since no valid expression is present. |
Input string with leading/trailing whitespace | Trim the input string to remove any leading/trailing whitespace before processing. |
Consecutive operators (e.g., 3 + - 2) | Handle the sign of the second operator by correctly parsing and applying to the subsequent number. |
Division by zero | Return 0, or throw an exception, depending on the specific requirements. |
Integer overflow during calculation | Use a larger integer type (e.g., long) or check for overflow before performing the calculation. |
Input string with invalid characters (e.g., letters) | Return 0, throw an exception, or filter out invalid characters before processing. |
Large numbers and number of operations | The stack based approach will scale to larger inputs and the integer type (int/long) choice affects range. |