Basic Calculator

Question

Implement a basic calculator to evaluate a simple expression string.

The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative integers and empty spaces .

You may assume that the given expression is always valid.

Some examples:

"1 + 1" = 2
" 2-1 + 2 " = 3
"(1+(4+5+2)-3)+(6+8)" = 23

Note: Do not use the eval built-in library function.

Tags

  • Stack
  • Math

Thought

Two solutions:

  • Without Reverse Polish notation(RPN)
  • With Reverse Polish notation(RPN)

Without Reverse Polish notation Reference: https://discuss.leetcode.com/topic/15806/easy-18-lines-c-16-lines-python Since the calculation here only involves '+' and '-', it is possible to consider the whole calculation process happens between the sum of all integers (including positive integer and negative integer). Then we can use a stack of sign symbol for calculation.

With Reverse Polish notation Reference: http://bookshadow.com/weblog/2015/06/09/leetcode-basic-calculator/ This we need to convert the expression to reverse polish notation at first and then calculate the result. The algorithm for converting the infix notation to reverse polish notation is followed as Shunting-yard algorithm. After converting it, the calculation process is simple.

Notice Even though the efficiency of the algorithm without RPN is better, the practice with RPN is also recommended, because it is more universal in different problems.

Code

Without Reverse Polish notation

class Solution(object):
    def calculate(self, s):
        """
        :type s: str
        :rtype: int
        """
        result = 0
        i, sign = 0, [1, 1]
        while i < len(s):
            c = s[i]
            if c.isdigit():
                start = i
                while i < len(s) and s[i].isdigit():
                    i += 1
                result += sign.pop() * int(s[start:i])
                continue
            if c in '+-(':
                if c in '+(':
                    sign += [sign[-1]]
                else:
                    sign += [-sign[-1]]
            elif c == ')':
                sign.pop()
            i += 1
        return result

With Reverse Polish notation

class Solution(object):
    priorityDict = {'+': 1, '-':1, '*':2, '/':2}

    def toRPN(self, s):
        i = 0
        rpnList, stack = [], []
        while i < len(s):
            c = s[i]
            if c.isdigit():
                start = i
                while i < len(s) and s[i].isdigit():
                    i += 1
                rpnList.append(s[start:i])
                continue
            if c in self.priorityDict.keys():
                while stack and stack[-1] in self.priorityDict.keys() and self.priorityDict[stack[-1]] >= self.priorityDict[c]:
                    rpnList.append(stack.pop())
                stack.append(c)
            elif c == '(':
                stack.append(c)
            elif c == ')':
                while stack and stack[-1] != '(':
                    rpnList.append(stack.pop())
                stack.pop()
            i += 1
        while stack:
            rpnList.append(stack.pop())
        return rpnList

    def calculate(self, s):
        """
        :type s: str
        :rtype: int
        """
        if s == '':
            return 0
        rpnList = self.toRPN(s)
        stack = []
        for item in rpnList:
            if item not in self.priorityDict.keys():
                stack.append(int(item))
            else:
                reg2 = stack.pop()
                reg1 = stack.pop()
                if item == '+':
                    stack.append(reg1 + reg2)
                elif item == '-':
                    stack.append(reg1 - reg2)
                elif item == '*':
                    stack.append(reg1 * reg2)
                else:
                    stack.append(reg1 / reg2)
        return stack[0]

results matching ""

    No results matching ""