基本计算器 II

双栈实现基本计算器 II

题目

(1)给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
(2)整数除法仅保留整数部分。
(3)示例1如下:
输入:s = “3+2*2”
输出:7
(4)示例2如下:
输入:s = " 3+5 / 2 "
输出:5

解决思路

  • 用双栈实现基本计算器,其中一个栈为操作数栈,另外一个栈为运算符栈。
  • 第一步:先将表达式拆分为两部分,一部分只包含操作数,另外一部分只包含运算符。
  • 第二步:若当前即将入栈的运算符oper1的优先级小于等于栈顶运算符oper2的优先级时,则先根据栈顶的运算符oper2对操作数栈顶元素和倒数第二个元素进行运算,然后将结果放入操作数栈中。
  • 第三步:将运算符栈的栈顶元素oper2弹出。然后判断此时运算符栈的栈顶元素oper2_new的优先级和即将入栈的运算符oper1的优先级,若oper1的优先级小于等于oper2_new的优先级,则重复第二步。
  • 第四步:将即将入栈的运算符oper1压入运算符栈中。
  • 详细步骤如下所示:
    在这里插入图片描述

代码

  • C++代码
# include <stdio.h>
# include <string>
# include <stack>

using namespace std;


class Solution {
public:
    // 获取运算符优先级
    int level(char s) {
        switch (s) {
            case '@':
                return -1;
            case '+':
            case '-':
                return 1;
            case '*':
            case '/':
                return 2;
            default:
                return 0;   // 0表示当前字符是数字,用于将字符转换成数值
        }
    }

    // 根据运算符进行计算
    int myCalculate(int a, int b, char oper) {
        switch (oper) {
            case '+':
                return a + b;
            case '-':
                return a - b;
            case '*':
                return a * b;
            case '/':
                return a / b;
            default:
                return 0;
        }
    }

    int calculate(string s) {
        stack<int> num;         // 存储操作数的栈。
        stack<char> operation;  // 存储运算符的栈。
        int n = 0;              // 某个具体的数值(字符串数值转换为整数)。
        
        // 技巧:自定义一个操作符@,使其运算优先级最低,并将@拼接在字符串的最后,用于简化操作。
        // 当遍历字符串遇到@操作符时,会先对操作数栈中剩下的两个数进行运算,然后再将结果压入操作数栈中。
        // 由于使用了操作符@,简化了返回结果前的最后一步操作流程。 如果没有操作符@,则要设定条件来判断哪个操作符是最后一个操作符。
        // 然后将剩余的操作符对应的操作运算完,再返回最终结果。
        s += '@';

        // 1. 遍历字符串中的每个字符,将数值和运算符分开,并根据运算符进行相应的操作
        for (int i = 0; i < s.size(); i++) {
            if (' ' == s[i]) {
                continue;
            }

            // 2. 当前字符为数值
            // 第一步:获取字符串中的数值(剩下的字符为运算符)。
            if (0 == level(s[i])) {
                n = n * 10 + (s[i] - '0');  // 将字符串转换成数值,如将“123”变成整数123
                continue;
            }
            num.push(n);    // 将数值放入操作数栈
            n = 0;          // 将值设置为0,便于计算下一个值。

            // 3. 当前字符为运算符,根据运算符进行过相应的运算
            // 第二步:当前运算符的优先级小于等于栈顶元素的优先级时,先根据栈顶运算符对栈顶和倒数第二个元素进行运算。
            // 并将运算结果压入操作数栈中,然后从运算符栈中弹出栈顶运算符,然后将当前运算符压入运算符栈。
            while (!operation.empty() && level(s[i]) <= level(operation.top())) {
                int b = num.top();
                num.pop();
                int a = num.top();
                num.pop();
                num.push(myCalculate(a, b, operation.top()));   // 将运算结果压入栈中。
                operation.pop();    // 第三步:将运算符栈的栈顶元素弹出。
            }

            // 第四步:将即将入栈的运算符压入运算符栈中。
            // 注意:要等运算符栈顶中优先级高的运算符有运算完后,再将当前运算符压入运算符栈中。
            operation.push(s[i]);
        }
        // 因为使用了自定义的@运算符,所以返回结果前不需要进行复杂的操作,只需返回栈顶元素即可。
        return num.top();
    }
};


int main() {
    string s = "3+2*2";
    Solution *solution = new Solution();
    printf("%d\n", solution->calculate(s));
    return 0;
}
  • Python代码
# -*- coding: utf-8 -*-

from typing import List
import math


class Solution:
    def __init__(self):
        pass

    # 获取运算符优先级
    def level(self, s: str) -> int:
        if '@' == s:
            return -1
        elif '+' == s or '-' == s:
            return 1
        elif '*' == s or '/' == s:
            return 2
        else:
            return 0    # 0表示当前字符是数字,用于将字符转换成数值

    # 根据运算符进行计算
    def myCalculate(self, a: int, b: int, oper: str) -> int:
        if '+' == oper:
            return a + b
        elif '-' == oper:
            return a - b
        elif '*' == oper:
            return a * b
        elif '/' == oper:
            return math.floor(a / b)

    def calculate(self, s: str) -> int:
        num: List[int] = []         # 存储操作数的栈。
        operation: List[str] = []   # 存储运算符的栈。
        n: int = 0                  # 某个具体的数值(字符串数值转换为整数)。

        # 技巧:自定义一个操作符 @,使其运算优先级最低,并将 @ 拼接在字符串的最后,用于简化操作。
        # 当遍历字符串遇到 @ 操作符时,会先对操作数栈中剩下的两个数进行运算,然后再将结果压入操作数栈中。
        # 由于使用了操作符 @,简化了返回结果前的最后一步操作流程。 如果没有操作符 @,则要设定条件来判断哪个操作符是最后一个操作符。
        # 然后将剩余的操作符对应的操作运算完,再返回最终结果。
        s += '@'

        # 1. 遍历字符串中的每个字符,将数值和运算符分开,并根据运算符进行相应的操作
        for i in s:
            if ' ' == i:
                continue

            # 2. 当前字符为数值
            # 第一步:获取字符串中的数值(剩下的字符为运算符)。
            if 0 == self.level(i):
                # 将字符串转换成数值,如将“123”变成整数123
                n = n * 10 + int(i)
                continue
            num.append(n)       # 将数值放入操作数栈
            n = 0               # 将值设置为0,便于计算下一个值。

            # 3. 当前字符为运算符,根据运算符进行过相应的运算
            # 第二步:当前运算符的优先级小于等于栈顶元素的优先级时,先根据栈顶运算符对栈顶和倒数第二个元素进行运算。
            # 并将运算结果压入操作数栈中,然后从运算符栈中弹出栈顶运算符,然后将当前运算符压入运算符栈。
            while operation and self.level(i) <= self.level(operation[-1]):
                b = num.pop()   # 栈顶元素
                a = num.pop()   # 倒数第二个元素
                num.append(self.myCalculate(a, b, operation[-1]))   # 将运算结果压入栈中。
                operation.pop()     # 第三步:将运算符栈的栈顶元素弹出。

            # 第四步:将即将入栈的运算符压入运算符栈中。
            # 注意:要等运算符栈顶中优先级高的运算符有运算完后,再将当前运算符压入运算符栈中。
            operation.append(i)
        # 因为使用了自定义的@运算符,所以返回结果前不需要进行复杂的操作,只需返回栈顶元素即可。
        return num[-1]


def main():
    solution = Solution()
    s = "3+2*2"
    print(solution.calculate(s))


if __name__ == "__main__":
    main()

说明

  • 对应LeetCode第227题。
  • 链接:https://leetcode-cn.com/problems/basic-calculator-ii/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值