You are given an array of strings tokens
that represents an arithmetic expression in a Reverse Polish Notation. Evaluate the expression. Return an integer that represents the value of the expression. The valid operators are '+', '-', '*', and '/'. Each operand may be an integer or another expression. The division between two integers always truncates toward zero. There will not be any division by zero. The input represents a valid arithmetic expression in a reverse polish notation. The answer and all the intermediate calculations can be represented in a 32-bit integer.
For example:
Input: tokens = ["2","1","+","3","*"] Output: 9 Explanation: ((2 + 1) * 3) = 9
Input: tokens = ["4","13","5","/","+"] Output: 6 Explanation: (4 + (13 / 5)) = 6
How would you approach this problem and what would be the time and space complexity?
## Evaluating Reverse Polish Notation
This problem requires us to evaluate an arithmetic expression given in Reverse Polish Notation (RPN). RPN, also known as postfix notation, places operators after their operands. We can efficiently solve this using a stack.
### Naive Solution
A naive approach involves iterating through the tokens. If we encounter a number, we push it onto a stack. If we encounter an operator, we pop the top two numbers from the stack, perform the operation, and push the result back onto the stack. This works because RPN naturally lends itself to stack-based evaluation.
### Optimal Solution
The optimal solution is essentially the same as the naive solution, but with careful consideration of integer division (truncating towards zero) and handling potential errors.
```python
class Solution:
def evalRPN(self, tokens: list[str]) -> int:
stack = []
operators = {
'+': lambda a, b: a + b,
'-': lambda a, b: a - b,
'*': lambda a, b: a * b,
'/': lambda a, b: int(a / b)
}
for token in tokens:
if token in operators:
operand2 = stack.pop()
operand1 = stack.pop()
result = operators[token](operand1, operand2)
stack.append(result)
else:
stack.append(int(token))
return stack[0]
Example Usage:
tokens1 = ["2","1","+","3","*"]
print(Solution().evalRPN(tokens1)) # Output: 9
tokens2 = ["4","13","5","/","+"]
print(Solution().evalRPN(tokens2)) # Output: 6
tokens3 = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
print(Solution().evalRPN(tokens3)) # Output: 22
The run-time complexity is O(n), where n is the number of tokens in the input array. We iterate through the tokens array once. Each operation (pushing and popping from the stack) takes O(1) time.
The space complexity is O(n) in the worst-case scenario. In the worst case, the stack might contain all the operands before encountering operators. For example, an input like ["1", "2", "3", "4", "+", "+", "+"]
would result in the numbers 1, 2, 3, and 4 being on the stack before any operation is performed.
["5"]
), the algorithm correctly returns that number.long
data types or checking for overflow).