You are tasked with implementing a basic calculator to evaluate a string expression. The expression may contain digits, the four basic arithmetic operations (+, -, *, /), and parentheses. Your calculator should follow the standard order of operations (PEMDAS/BODMAS).
Details:
eval()
function or similar built-in functions.Example:
Input: "1 + 1"
Output: 2
Input: "6-4/2"
Output: 4
Input: "2*(5+5*2)/3+(6/2+8)"
Output: 21
Input: "(2+6* 3+5-(3*14/7+2)*5)+3"
Output: -12
Explain your approach, analyze the time and space complexity, and handle any edge cases in your code. Provide test cases that you used to ensure the robustness of your code.
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 to this calculator problem is like trying every single way to evaluate the expression. We explore all possible orders of operations to find the correct result. It's very inefficient but guarantees we'll eventually find the right answer if we check everything.
Here's how the algorithm would work step-by-step:
def basic_calculator_iii_brute_force(expression):
# Brute force approach is not feasible for this problem
# Returning a placeholder value
return evaluate_expression(expression)
def evaluate_expression(expression_string):
expression_string = expression_string.replace(' ', '')
if not any(op in expression_string for op in ['+', '-', '*', '/']):
return int(expression_string)
# Perform multiplication and division first
index = 0
while index < len(expression_string):
if expression_string[index] == '*' or expression_string[index] == '/':
left_operand_end = index - 1
while left_operand_end >= 0 and expression_string[left_operand_end].isdigit():
left_operand_end -= 1
left_operand_start = left_operand_end + 1
right_operand_start = index + 1
right_operand_end = right_operand_start
while right_operand_end < len(expression_string) and expression_string[right_operand_end].isdigit():
right_operand_end += 1
left_operand = int(expression_string[left_operand_start:index])
right_operand = int(expression_string[index + 1:right_operand_end])
# Evaluate mul or div operations
if expression_string[index] == '*':
result = left_operand * right_operand
else:
result = left_operand // right_operand
expression_string = expression_string[:left_operand_start] + str(result) + expression_string[right_operand_end:]
index = 0
else:
index += 1
# Perform addition and subtraction
index = 0
while index < len(expression_string):
if expression_string[index] == '+' or expression_string[index] == '-':
left_operand_end = index - 1
while left_operand_end >= 0 and expression_string[left_operand_end].isdigit():
left_operand_end -= 1
left_operand_start = left_operand_end + 1
right_operand_start = index + 1
right_operand_end = right_operand_start
while right_operand_end < len(expression_string) and expression_string[right_operand_end].isdigit():
right_operand_end += 1
left_operand = int(expression_string[left_operand_start:index])
right_operand = int(expression_string[index + 1:right_operand_end])
# Evaluate addition or subtraction
if expression_string[index] == '+':
result = left_operand + right_operand
else:
result = left_operand - right_operand
expression_string = expression_string[:left_operand_start] + str(result) + expression_string[right_operand_end:]
index = 0
else:
index += 1
return int(expression_string)
This calculator problem is about evaluating an expression given as a string. The efficient way to solve it is to recognize the order of operations (PEMDAS/BODMAS) and use a stack-based approach to keep track of intermediate results and handle parentheses correctly.
Here's how the algorithm would work step-by-step:
def calculate(expression_string):
current_number = 0
operation = '+'
stack = []
for i in range(len(expression_string)):
character = expression_string[i]
if character.isdigit():
current_number = (current_number * 10) + int(character)
if character in '+-*/()' or i == len(expression_string) - 1:
if character == '(': # Start a sub-calculation.
count = 1
j = i + 1
while count > 0:
if expression_string[j] == '(':
count += 1
elif expression_string[j] == ')':
count -= 1
j += 1
current_number = calculate(expression_string[i + 1:j - 1])
i = j - 1 # Advance index after evaluating sub-expression.
if operation == '+':
stack.append(current_number)
elif operation == '-':
stack.append(-current_number)
elif operation == '*': # Immediate multiplication.
stack.append(stack.pop() * current_number)
elif operation == '/': # Immediate division.
stack.append(int(stack.pop() / current_number))
operation = character
current_number = 0
result = 0
while stack: # Sum remaining values in the stack.
result += stack.pop()
return result
Case | How to Handle |
---|---|
Empty input string | Return 0 immediately as there's nothing to evaluate |
String contains only whitespace | Return 0 after trimming whitespace if empty, or handle the whitespace gracefully during parsing by skipping it. |
String starts with an operator (+, -, *, /) | Prepend '0' to the string to handle initial operators by treating them as unary |
Consecutive operators (e.g., 2 + - 3) | Handle unary operators correctly by parsing the operator and its subsequent operand |
Division by zero | Throw an exception or return a predefined error value to avoid undefined behavior |
Integer overflow during calculation | Use a larger data type (e.g., long) or check for overflow conditions before performing the operation and throw an exception if needed |
Very long input string exceeding stack limits | Use an iterative approach instead of recursion to avoid stack overflow for large expressions |
Input contains invalid characters | Reject the input string or skip the invalid characters and continue parsing the rest. |