LeetCode – Evaluate Reverse Polish Notation

Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, *, /. Each operand may be an integer or another expression. For example:

  ["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9
  ["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6

1. Naive Approach

This problem can be solved by using a stack. We can loop through each element in the given array. When it is a number, push it to the stack. When it is an operator, pop two numbers from the stack, do the calculation, and push back the result.

Evaluate Reverse Polish Notation

The following is the code. However, this code contains compilation errors in leetcode. Why?

public class Test {
 
	public static void main(String[] args) throws IOException {
		String[] tokens = new String[] { "2", "1", "+", "3", "*" };
		System.out.println(evalRPN(tokens));
	}
 
	public static int evalRPN(String[] tokens) {
		int returnValue = 0;
		String operators = "+-*/";
 
		Stack<String> stack = new Stack<String>();
 
		for (String t : tokens) {
			if (!operators.contains(t)) { //push to stack if it is a number
				stack.push(t);
			} else {//pop numbers from stack if it is an operator
				int a = Integer.valueOf(stack.pop());
				int b = Integer.valueOf(stack.pop());
				switch (t) {
				case "+":
					stack.push(String.valueOf(a + b));
					break;
				case "-":
					stack.push(String.valueOf(b - a));
					break;
				case "*":
					stack.push(String.valueOf(a * b));
					break;
				case "/":
					stack.push(String.valueOf(b / a));
					break;
				}
			}
		}
 
		returnValue = Integer.valueOf(stack.pop());
 
		return returnValue;
	}
}

The problem is that switch string statement is only available from JDK 1.7. Leetcode apparently use a JDK version below 1.7.

2. Accepted Solution

If you want to use switch statement, you can convert the above by using the following code which use the index of a string "+-*/".

public class Solution {
    public int evalRPN(String[] tokens) {
 
        int returnValue = 0;
 
        String operators = "+-*/";
 
        Stack<String> stack = new Stack<String>();
 
        for(String t : tokens){
            if(!operators.contains(t)){
                stack.push(t);
            }else{
                int a = Integer.valueOf(stack.pop());
                int b = Integer.valueOf(stack.pop());
                int index = operators.indexOf(t);
                switch(index){
                    case 0:
                        stack.push(String.valueOf(a+b));
                        break;
                    case 1:
                        stack.push(String.valueOf(b-a));
                        break;
                    case 2:
                        stack.push(String.valueOf(a*b));
                        break;
                    case 3:
                        stack.push(String.valueOf(b/a));
                        break;
                }
            }
        }
 
        returnValue = Integer.valueOf(stack.pop());
 
        return returnValue;
 
    }
}
Category >> Algorithms  
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:
<pre><code> 
String foo = "bar";
</code></pre>
  • Greg Mueller

    Thanks Ryan, I tried this and found an error – in eval_op, you are missing the ‘:’ before each return. Also you named your main function ‘eval’, which overwrites the built-in eval function.

    I refactored your code down to this. The main difference is that I am building a string that looks like Python code and then calling eval on that string. Also, I am storing the numbers as strings, since I am not forcing the intergers to flow, or float to integer.


    def rpn(expr):
    s = []
    expr = expr.split() if type(expr) == type('') else expr
    for item in expr:
    if item.isnumeric():
    s.append(int(item))
    elif item in {'+', '-', '*', '/'}:
    intermediate_expr = ' '.join((str(s.pop()), item, str(s.pop())))
    s.append(eval(intermediate_expr))
    else:
    raise ValueError('Invalid value: ' + item)
    return s.pop()

    rpn('4 13 5 / +')
    rpn(["2", "1", "+", "3", "*"])

  • bimal prasad pandey

    thanx for it

  • Ryan Shaw

    Python solution:

    def eval_op(land, rand, op):
    if (op == '-') return land - rand
    if (op == '+') return land + rand
    if (op == '/') return land / rand
    if (op == '*') return land * rand
    raise ValueError('unrecognized op: ' + op)

    def is_op(c):
    return c == '+' or c == '-' or c == '*' or c == '/'

    def eval(expr):
    s = []
    for c in expr:
    if not is_op(c): s.append(int(c))
    else:
    rand, land = s.pop(), s.pop()
    s.append(eval_op(land, rand, c))
    return s.pop()

  • Abhishek Roy

    This may be due to lowercase “s” in “string”. Try using “String” instead of “string” as shown below,
    Stack stack = new Stack();

  • srj_michael

    Stack stack = new Stack();
    Showing error as :type stack does not take parameter

  • srj_michael

    It’s showing error.
    error: type stack does not take parameter.

  • Yunxiao Zou

    naive approach works for current Leetcode Java OJ

  • Taylor Annaterre
  • meha

    I was evaluating the second eg. i.e [“4”, “13”, “5”, “/”, “+”] -> (4 + (13 / 5)) -> 6 and solution is 4 instead of 6, because you pop 5 and then 13 ==> which will give you 5/13 =0 and hence the expression will result in 4.

  • Parag Chaudhari

    There is a bug in this code, first pop() must be a right operand and second pop() must be a left operand.

    Also, include following Edge Cases:
    1. You should check before returning that stack contains only one element.
    2. You must check divide by zero error for division operation
    3. You must handle unary operators e.g. factorial (!)
    4. Before performing any binary operation you must check whether stack has 2 operands.
    5. Before performing any unary operation you must check whether stack has 1 operand.

  • anonymous

    Here it is in Ruby if anyone is curious:

    def evaluate(expression)
    stack = []
    until expression.empty?
    a = expression.shift
    if (a.eql?(“+”) || a.eql?(“*”) || a.eql?(“-“) || a.eql?(“/”))
    x, y = stack.pop, stack.pop
    stack.push y.send(a, x)
    else
    stack.push a.to_i
    end
    end
    stack.first
    end
    evaluate [“4”, “13”, “5”, “/”, “+”]
    #=> 6

  • cg22165

    Better to use a Stack of Integers. Boxing and unboxing should be more efficient than creating and garbage collecting a lot of Strings.

    Better to wrap most of the operation and data type conversions in a try-catch. The catch can simply return “Data error”, “Invalid expression”, or similar.

    The pop of a and b should be reversed. “0 1 /” is valid, but “1 0 /” is an error.

    Honey badger doesn’t care whether you use ints, doubles, bigdecimals, whatever. They are looking for a good algorithm.

  • sebastian

    always a and b will be an int ? dont you think that maybe b could be null ? and in this case you wil have problems with the operations.

  • ryanlr

    It does not belong here, and can you put the code inside <pre> tags?

  • Salil Surendran

    What do you guys think of this solution. This is an O(n) solution

    private String findLongestPalindromicSubString(String str){

    if(str == null || str.length() == 0)
    return null;
    else if(str.length() == 1)
    return str;
    else{
    //Traverse down the string and which is each character
    //check this logic.
    int index=1;
    String longestPalindrome=null;
    while(index < str.length()/*||
    (longestPalindrome != null && str.length() – index 2 && str.charAt(index) == str.charAt(index – 2))
    currentPalindrome=readPalindrome(index – 2, index, str);

    if(currentPalindrome != null){
    if(longestPalindrome == null || currentPalindrome.length() > longestPalindrome.length())
    longestPalindrome=currentPalindrome;
    index+=currentPalindrome.length() / 2;
    }else
    index++;
    }
    return longestPalindrome;
    }
    }

  • I also don’t understand why the accepted solution uses Integer, it should use Double or at least Float.

  • Julien Dreux

    This implementation makes wrong assumptions about the pop/push methods on arrays. Pop and push act at the end of the array, the shift and unshift methods should be used instead.

  • themansitiwari

    what if we want the user to give in the input? like what if we have two digit or three digit numbers separated by comma or space?

  • Dongyon Kang

    wouldn’t b/a return an integer, which could be incorrect in cases such as “1/2” since b and a are both ints?

  • Axel Hadfeg

    The problem presented above is for a reverse polish notation (or postfix notation).
    The problem you describe is in standard infix format. Postfix notation always assumes you have two operands preceding an operator. Thus your case doesn’t really apply. You could, however, make an error check for special cases that fall beyond the method’s assumptions. For example 2* would be 2 *1, or 2 *0, whatever you deem fit.

  • codingfacts

    what about this case. 2*3-1

  • Henco Appel

    Thought I’d point out something slightly nicer than using the index, in Java 1.6 you can switch on chars, so why not just switch on t.charAt(0) for cases ‘+’, ‘-‘, ‘*’, ‘/’. Also means that you don’t have to do a search, even though it’s only a String of 4 characters.

  • Henco Appel

    The hole point of RPN is that you don’t need the brackets, the order of the numbers and operators is what defines the order of the operations, so no need for brackets or BODMAS.

  • shreyas KN

    hey are we not supposed to apply the BODMAS rules here ?

  • ryanlr

    Changed. Thanks!

  • JeffreyT

    for the naive solution, you may want to replace “a – b” with “b – a” in case “-” of switch block.