算法---LeetCode 227. 基本计算器 II

1. 题目

原题链接

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。

示例 1:

输入:s = “3+2*2”
输出:7

示例 2:

输入:s = " 3/2 "
输出:1

示例 3:

输入:s = " 3+5 / 2 "
输出:5

提示:

1 <= s.length <= 3 * 105
s 由整数和算符 (’+’, ‘-’, ‘*’, ‘/’) 组成,中间由一些空格隔开
s 表示一个 有效表达式
表达式中的所有整数都是非负整数,且在范围 [0, 231 - 1] 内
题目数据保证答案是一个 32-bit 整数

Related Topics 栈 字符串
👍 385 👎 0

2. 题解

2.1 解法1: 一个栈

主要思想:

由于只有 加减乘除 四种运算符, 且有优先关系, 可以先进行所有 乘除 运算, 并将运算后的结果放回 栈中, 最后对栈中的数进行 加减 运算, 最终得到结果

算法流程

用一个栈保存数值, 变量 preSign 记录每个数字之前的运算符, 对第一个数字, 运算符记为 +, 之后遍历字符串的每个字符, 进行如下流程:

  1. 若 为数字, 则计算该数字的值转化为 整型数 num
  2. 若读到一个运算符,或者遍历到字符串末尾,即认为是遍历到了数字末尾, 根据 preSign 对 num 以及栈顶元素进行计算, 计算完成后将结果加入栈中, 同时注意处理完该数字后,更新 preSign 为当前遍历的字符。同时将 num置 0

最后遍历完字符串 s 后,将栈中元素累加,即为该字符串表达式的值。

    class Solution {
        public int calculate(String s) {
            Deque<Integer> stack = new ArrayDeque<>();
            int num = 0;
            char preSign = '+';
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                if (Character.isDigit(c)) { // 计算整数值
                    num = num * 10 + c - '0';
                }
                if ((!Character.isDigit(c) && c != ' ') || i == s.length() - 1) { // 根据运算符计算并入栈
                    if (preSign == '+') stack.push(num);
                    else if (preSign == '-') stack.push(-num);
                    else if (preSign == '*') stack.push(stack.pop() * num);
                    else if (preSign == '/') stack.push(stack.pop() / num);
                    preSign = c;
                    num = 0;
                }
            }
            int ans = 0;
            while (!stack.isEmpty()) {
                ans += stack.pop();
            }
            return ans;
        }
    }

参考: 官方题解
先乘除再加减,用「栈」保存中间结果

2.2 解法2: 双栈法

一个栈用于保存操作数, 一个栈用于保存运算符

  1. 使用 map 保存运算符的优先级, 先对字符串进行预处理, 去除空格, 在栈顶加 0
  2. 遍历字符串的每个字符, 分别按操作数与运算符处理
    1. 操作数: 使用变量读取连续的数字, 并转化为 Integer型, 存入栈
    2. 运算符: 判断当前运算符与栈顶运算符的关系, 若当前>=栈顶, 计算栈内的值
  3. 最后, 将栈内剩余的数进行计算, 返回栈顶值

细节注意点:

  1. 若当前字符为数字, 获取数值后, 要将下标相应的赋值推进
  2. 若当前字符为运算符, 栈内运算符优先级 < 当前优先级时, 要退出 while 循环
    class Solution {
        // 定义一个map, 用于保存运算符优先级
        Map<Character, Integer> map = new HashMap<Character, Integer>() {{
            put('+', 1);
            put('-', 1);
            put('*', 2);
            put('/', 2);
        }};

        public int calculate(String s) {
            s = s.replaceAll(" ", "");
            Deque<Integer> nums = new ArrayDeque<>();
            Deque<Character> ops = new ArrayDeque<>();
            nums.addLast(0);
            char[] cs = s.toCharArray();
            for (int i = 0; i < cs.length; i++) {
                char c = cs[i];
                if (Character.isDigit(c)) {
                    int curNum = 0;
                    while (i < cs.length && Character.isDigit(cs[i])) {
                        curNum = curNum * 10 + (cs[i] - '0');
                        i++;
                    }
                    nums.addLast(curNum);
                    // 注意最终的 i 需要减 1, 因为for 循环i会 +1
                    i--;
                } else {
                    // 比较运算符
                    while (!ops.isEmpty()) {
                        char prevOp = ops.peekLast();
                        if (map.get(c) <= map.get(prevOp)) {
                            compute(nums, ops);
                        } else {
                            break;
                        }
                    }
                    ops.addLast(c);
                }
            }
            while (!ops.isEmpty()) {
                compute(nums, ops);
            }
            return nums.peekLast();
        }


        public void compute(Deque<Integer> nums, Deque<Character> ops) {
            if (ops.isEmpty() || nums.size() < 2) {
                return;
            }
            char op = ops.pollLast();
            int b = nums.pollLast();
            int a = nums.pollLast();
            switch (op) {
                case '+':
                    nums.addLast(a + b);
                    break;
                case '-':
                    nums.addLast(a - b);
                    break;
                case '*':
                    nums.addLast(a * b);
                    break;
                case '/':
                    nums.addLast(a / b);
                    break;
            }
        }
    }

参考: 使用「双栈」解决「究极表达式计算」问题 …

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值