LeetCode 772 基本計(jì)算器 III 非遞歸解法

由于是一道會(huì)員專享的加練題,所以題解很少,并且大都是在227基本計(jì)算器II的基礎(chǔ)上,對(duì)括號(hào)內(nèi)的運(yùn)算直接做了遞歸處理,此外還有一些更慢的算法。這里分享一個(gè)非遞歸的思路,基于世界上最簡(jiǎn)單的語(yǔ)言Python實(shí)現(xiàn)。

題目描述:

實(shí)現(xiàn)一個(gè)基本的計(jì)算器來(lái)計(jì)算簡(jiǎn)單的表達(dá)式字符串。
表達(dá)式字符串可以包含左括號(hào) (和右括號(hào)),加號(hào) + 和減號(hào) -,非負(fù) 整數(shù)和空格 。
表達(dá)式字符串只包含非負(fù)整數(shù), +, -, *, / 操作符,左括號(hào) ( ,右括號(hào) )和空格。整數(shù)除法需要向下截?cái)唷?br> 你可以假定給定的字符串總是有效的。所有的中間結(jié)果的范圍為 [-2147483648, 2147483647]。
一些例子:
"1 + 1" = 2
" 6-4 / 2 " = 4
"2*(5+5*2)/3+(6/2+8)" = 21
"(2+6* 3+5- (3*14/7+2)*5)+3"=-12
注:不要 使用內(nèi)置庫(kù)函數(shù) eval。
來(lái)源:力扣(LeetCode)鏈接:https://leetcode-cn.com/problems/basic-calculator-iii著作權(quán)歸領(lǐng)扣網(wǎng)絡(luò)所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系官方授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

在【基本計(jì)算器II】的基礎(chǔ)上,我們可以用遞歸的方法將括號(hào)中的運(yùn)算作為參數(shù)傳入,直接做遞歸運(yùn)算,這是最為方便快捷的做法。此外,我們也可以不使用遞歸,防止括號(hào)過(guò)多的情況下函數(shù)棧溢出。

相比于【基本計(jì)算器II】,我們需要額外考慮的只有括號(hào)的處理,其他操作都基本相同。在解題之前,我們可以分析出一個(gè)規(guī)律:'('前面一定不是數(shù)字,而其他符號(hào)前面一定是數(shù)字。

因此,遇到'('符號(hào),我們可以把它前面的符號(hào)壓入棧中做個(gè)標(biāo)記,在處理完括號(hào)里的運(yùn)算后,再回頭做對(duì)應(yīng)的運(yùn)算。遇到')'符號(hào)時(shí),我們需要先將棧頂?shù)乃袛?shù)字累加,直到棧頂變成運(yùn)算符字符串為止。此時(shí)意味著我們已經(jīng)把這對(duì)括號(hào)內(nèi)的運(yùn)算都處理完了,得到了括號(hào)內(nèi)的運(yùn)算結(jié)果。將棧頂?shù)倪\(yùn)算符取出后,我們對(duì)括號(hào)的結(jié)果進(jìn)行對(duì)應(yīng)的運(yùn)算就可以了。

Python實(shí)現(xiàn)的代碼如下:


from collections import deque

class Solution:

    # Deal with the operations

    def solve(self, operand: int, sign: str, stack: deque) -> int:

        if sign == '+':
            return operand
        elif sign == '-':
            return -operand
        elif sign == '*':
            return stack.pop() * operand
        elif sign == '/':
            return int(stack.pop() / operand)

    def calculate(self, s: str) -> int:
        stack = deque()
        operand = 0
        sign = '+'

        for c in s:
            if c == ' ':
                # Ignore the space
                continue
            elif c.isdigit():
                operand = operand * 10 + int(c)
            elif c == '(':
                # An integer cannot be just before a '(', so only save the previous operator here
                stack.append(sign)
                sign = '+'
            else:
                # Do the default calculation
                result = self.solve(operand, sign, stack)

                operand = 0

                if c == ')':
                    # Summate all the intergers on the top of a stack until meet an operator, which means
                    # we need to do the corresponding operation with the summation value as an operand
                    while isinstance(stack[-1], int):
                        result += stack.pop()

                    sign = stack.pop()

                    operand = self.solve(result, sign, stack)
                    sign = '+'

                else:
                    # Push the result value to the stack for later summation
                    # Save the operator for calculation in a coming loop

                    sign = c

                    stack.append(result)

        # The calculation doesn't finish here. We always do actual calculation in later loops, so
        # at present we should deal with the operand gotten in the last loop.
        last = self.solve(operand, sign, stack)
        stack.append(last)

        # + and - have the lowest priority
        return sum(stack)

在這樣的解法中,運(yùn)算時(shí)間約和字符串長(zhǎng)度 N 成正比,復(fù)雜度為 O(N);需要的棧長(zhǎng)度不超過(guò)字符串中運(yùn)算符的數(shù)量,小于 N/2,復(fù)雜度為 O(N)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容