Evaluate Reversed Polish Notation

LeetCode problem: 150. Evaluate Reverse Polish Notation

## Problem description

Evaluate the value of an arithmetic expression in Reverse Polish Notation.

Valid operators are `+`, `-`, `*`, `/`. Each operand may be an integer or another expression.

Note
* Division between two integers should truncate toward zero.
* The given RPN expression is always valid. That means the expression would always evaluate to a result and there won't be any divide by zero operation.

Example 1
* **Input:** `["2", "1", "+", "3", "*"]`
* **Output:** 9
* **Explanation:** `((2 + 1) * 3) = 9`

Example 2
* **Input:** `["4", "13", "5", "/", "+"]`
* **Output:** 6
* **Explanation:** `(4 + (13 / 5)) = 6`

Example 3
* **Input:** `["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]`
* **Output:** 22
* **Explanation:**
```
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

```

## Analysis

Given that all tokens and the whole input array is valid, in this problem we only encounter two types of tokens:

* **Integers**: **+** or **-** sign (optional) followed by digits
* **Operators**: `**+ - \* /**`

So we can use a iterator to go over the tokens from left to right.

Here are the things we do respectively when encountering each type of token:

1. When encountering an **integer**, we **save this integer** for later use in computation.
2. When encountering an **operator**, we perform the arithmetic operation using the **two operands we have most recently encountered**, and **save the result** for further computation.
	* This problem requires us to perform the computation operations from left to right in the order in which we *receive the operators*. There is no operator precedence issue to concern.

* See the section #Checking token type for the procedure of checking the token type.
* See the section #Data structure for how to store the intermediate results.

When we have went over the last token, the result is obtained.

### Checking token type

Since all tokens are valid, we can check the token type using the following method:

* Check if one string is an integer:
	1. An empty string is not an integer.
	2. If we have the sign **+** or **-**, then check if index 1 is a digit.
	3. Otherwise, check if index 0 is a digit.
* All strings that are not integers are operators.

### Data structure

We can keep a **data stack** to store the necessary integers in the intermediate steps of computation.

As we iterate over the input, we continuously modify the data stack.

* When we encounter an integer, we push this integer onto the data stack.
* When we encounter an operator:
	1. Pop the last two integers from the data stack to use as operands (`op1` and `op2`). Note that `op2` is popped first, and then `op1`.
	2. Compute the intermediate result (or the final result, if the data stack is empty at this moment) using the two operands and the operator.
	3. Push this computed result onto the data stack. This result will be used in further computations.

At the end, the data stack will contain exactly one integer, which is our final result.

### Complexity analysis

#### Time complexity

* We go over each token exactly once. So the time to iterate over them is O(n).
* Checking whether a token is an integer or an operator takes O(1) time.
* Each computation takes O(1) time.
* Popping from or pushing to the data stack takes O(1) time.

So the total time complexity is **O(n)**.

#### Space complexity

Stack
What we need on stack:
* Input string iterator
* Two integers to serve as operands
* Operator character

So the space complexity on stack is **O(1)**.
Heap
We maintain a data stack on the heap. The space complexity for this is **O(n)**, where *n* is the total number of input tokens.
* The number of integers in the input data is one half (round up) of the total number of tokens.
* Worst case example: `["1", "2", "3", "4", "5", "+", "-", "*", "/"]`. We need to store all integers into the data stack first. The data stack has its maximum size of O(n/2) = **O(n)**.

So the total space complexity is **O(n)**.

## Solution

### C++

```
class Solution {
private:
 static bool isNum(const std::string& str) {
 if (str.empty()) {
 return false;
 }

 if ((str[0] == '+') || (str[0] == '-')) {
 // signed number
 if (str.size() > 1) {
 return isdigit(str[1]);
 }
 else {
 return false;
 }
 }
 else {
 return isdigit(str[0]);
 }
 }

 static int computeStack(std::stack<int>& data, const char& op) {
 if (data.size() <= 1) {
 return 0;
 }

 // get two operands
 int op2 = data.top();
 data.pop();
 int op1 = data.top();
 data.pop();

 // compute result
 int result = 0;
 switch (op) {
 case '+':
 result = op1 + op2;
 break;
 case '-':
 result = op1 - op2;
 break;
 case '\*':
 result = op1 \* op2;
 break;
 case '/':
 result = op1 / op2;
 break;
 default:
 break;
 }

 // push result for next computation
 data.push(result);
 return result;
 }

public:
 int evalRPN(const std::vector<std::string>& tokens) {
 std::stack<int> data;
 for (auto& token: tokens) {
 if (isNum(token)) {
 data.push(std::stoi(token));
 }
 else {
 const char op = token[0];
 computeStack(data, op);
 }
 }

 if (data.empty()) {
 return 0;
 }
 else {
 return data.top();
 }
 }
};

```

### Java

```
class Solution {
 private static boolean isNum(String str) {
 if (str.isEmpty()) {
 return false;
 }

 if ((str.charAt(0) == '+') || (str.charAt(0) == '-')) {
 if (str.length() <= 1) {
 return false;
 }
 else {
 return Character.isDigit(str.charAt(1));
 }
 }
 else {
 return Character.isDigit(str.charAt(0));
 }
 }

 private static int computeStack(ArrayDeque<Integer> dataStack, char op) {
 if (dataStack.size() < 2) {
 return 0;
 }

 int op2 = dataStack.pollLast();
 int op1 = dataStack.pollLast();
 int result = 0;
 switch (op) {
 case '+':
 result = op1 + op2;
 break;
 case '-':
 result = op1 - op2;
 break;
 case '\*':
 result = op1 \* op2;
 break;
 case '/':
 result = op1 / op2;
 break;
 }

 dataStack.offerLast(result);
 return result;
 }

 public int evalRPN(String[] tokens) {
 ArrayDeque<Integer> data = new ArrayDeque<>();
 for (String token: tokens) {
 if (isNum(token)) {
 data.offerLast(Integer.parseInt(token));
 }
 else {
 computeStack(data, token.charAt(0));
 }
 }
 return data.peek();
 }
}

```

## Notes for programming

### C++

* String APIs: `std::string`
	+ To convert a string to an integer, use the `std::stoi` function (provided by the `<string>` header).
* To check if a character is a digit, use the `isdigit` function (provided by the `<cctype>` header).

### Java

* The `String` class: `java.lang.String`
	+ Get character at index *i*: use the `charAt(int index)` method.
* The `Character` class: `java.lang.Character`
	+ Check if a character is a digit: use the `isDigit(char ch)` method.
* The `Integer` class: `java.lang.Integer`
	+ To convert a string to an integer: use the `Integer.parseInt(String s)` method.
* The `ArrayDeque` class: `java.util.ArrayDeque<E>`
	+ To implement a stack, we only insert / remove at right ends.