快手 CodeTop LeetCode 227.基本计算器Ⅱ

思路:利用栈实现表达式求值。

1.对于表达式求值的问题,可以维护两个栈,一个nums栈用来记录数字,一个ops栈用来记录操作符,遍历表达式,当遇到操作符时就进行数的相应计算。

2.首先可以定义一个eval()函数,用于从数字栈nums中弹出两个数字a和b,再从操作符栈ops中弹出操作符号,进行计算后将结果数字加入到数字栈nums中。

3.然后从前往后扫描整个表达式:

(1)当遇到空格' '时,跳过。

(2)当遇到数字时,读取一个连续的完整数字,再将其加入到数字栈nums中。

(3)当遇到'+'、'-'、'*'、'/'运算符时,需要考虑优先级,可以用HashMap保存每种操作符的优先级。

(a)如果操作符栈ops的栈顶元素的优先级比当前遇到的操作符的优先级高或者相等,则while()循环进行eval()操作,即将数字栈nums栈顶的两个元素取出来,然后和操作符栈ops的栈顶操作符进行相应的计算,并将计算结果压回数字栈nums中(由于栈的先进后出的特点,后进来的优先级高的操作符会先被用于计算)。

(b)否则,将当前运算符压入操作符栈ops中。

(4)扫描完整个表达式后,如果操作符栈ops中还存在元素,则while循环进行eval()操作。

(5)最终数字栈nums剩下的那个元素就是最终的结果,return返回。

4.细节处理:

(1)由于运算符有优先级,所以设计一个哈希表来存储' + '' - '' * '' / '的优先级,我们将+和-设计为1优先级,将*和/设计为2优先级。

(2)考虑到表达式s的第一个数字可能为负数,因此我们给s开头添加一个字符0。

5.复杂度分析:

(1)时间复杂度:O(n),其中n是字符串s的长度。

(2)空间复杂度:O(n)。

附代码:

java 复制代码
class Solution {
    private LinkedList<Integer> nums = new LinkedList<>();
    private LinkedList<Character> ops = new LinkedList<>();
    private Map<Character,Integer> map = new HashMap<>();
    public int calculate(String s) {
        s = '0' + s; // 对开头是负数的处理
        map.put('+', 1);   //定义运算符的优先级
        map.put('-', 1);
        map.put('*', 2);
        map.put('/', 2);
        for(int i = 0; i < s.length();i ++)
        {
            char c = s.charAt(i);
            // 因为乘除法需要立即计算,所以采用的是增强for循环,而不是普通的for i索引for循环
            // 逐i位遍历(而非增强for循环的话),每一位都要判断空格(上一题增强for循环无需判断)
            if(c == ' ') continue;  // 跳过空格
            if(c >= '0' && c <= '9')  // c是数字,读取一个连续的数字
            {
                int x = 0;
                while(i < s.length() && s.charAt(i) >= '0' && s.charAt(i) <= '9'){
                    x = x * 10 + s.charAt(i++) - '0';
                }
                // 抵消循环内最后一次i++造成的额外增量
                i--;
                nums.push(x);
            }
            else  // c是操作符
            {     // ops栈非空并且栈顶操作符优先级大于等于当前操作符c的优先级,进行eval()计算
                while(!ops.isEmpty() && map.get(ops.peek()) >= map.get(c)){
                    // 栈里元素进行计算
                    eval();
                }
                // 再把当前操作符c入栈
                ops.push(c);
            }
        }
        while(!ops.isEmpty()){
            // 栈里元素进行计算
            eval();
        }
        // 所有的计算完毕,数字栈中只剩下了最后一个最终计算结果,return即可
        return nums.pop();
    }
    public void eval()
    {
        int b = nums.pop();
        int a = nums.pop();
        char c = ops.pop();
        int res = 0;
        if(c == '+') res = a + b;
        else if(c == '-') res = a - b;
        else if(c == '*') res = a * b;
        else res = a / b;
        // 结果入栈
        nums.push(res);
    }
}

ACM模式:

java 复制代码
import java.util.LinkedList;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

class Solution {
    private LinkedList<Integer> nums = new LinkedList<>();
    private LinkedList<Character> ops = new LinkedList<>();
    private Map<Character, Integer> map = new HashMap<>();

    public int calculate(String s) {
        // 清空之前的数据(防止多次调用)
        nums.clear();
        ops.clear();
        map.clear();

        s = '0' + s; // 对开头是负数的处理
        map.put('+', 1);   // 定义运算符的优先级
        map.put('-', 1);
        map.put('*', 2);
        map.put('/', 2);

        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            // 因为乘除法需要立即计算,所以采用的是增强for循环,而不是普通的for i索引for循环
            // 逐i位遍历(而非增强for循环的话),每一位都要判断空格(上一题增强for循环无需判断)
            if (c == ' ') continue;  // 跳过空格

            if (c >= '0' && c <= '9') {  // c是数字,读取一个连续的数字
                int x = 0;
                while (i < s.length() && s.charAt(i) >= '0' && s.charAt(i) <= '9') {
                    x = x * 10 + (s.charAt(i) - '0');
                    i++;
                }
                // 抵消循环内最后一次i++造成的额外增量
                i--;
                nums.push(x);
            } else {  // c是操作符
                // ops栈非空并且栈顶操作符优先级大于等于当前操作符c的优先级,进行eval()计算
                while (!ops.isEmpty() && map.get(ops.peek()) >= map.get(c)) {
                    // 栈里元素进行计算
                    eval();
                }
                // 再把当前操作符c入栈
                ops.push(c);
            }
        }

        while (!ops.isEmpty()) {
            // 栈里元素进行计算
            eval();
        }

        // 所有的计算完毕,数字栈中只剩下了最后一个最终计算结果,return即可
        return nums.pop();
    }

    private void eval() {
        int b = nums.pop();
        int a = nums.pop();
        char c = ops.pop();
        int res = 0;
        if (c == '+') res = a + b;
        else if (c == '-') res = a - b;
        else if (c == '*') res = a * b;
        else res = a / b;
        // 结果入栈
        nums.push(res);
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取表达式字符串(可能包含空格)
        String s = scanner.nextLine();

        // 计算结果
        Solution solution = new Solution();
        int result = solution.calculate(s);

        // 输出结果
        System.out.println(result);

        scanner.close();
    }
}
相关推荐
weixin_408099671 小时前
2026 AI生成图片快速去水印的5种实测方法(附在线工具 + Python/Java/PHP API代码)
java·人工智能·python·api接口·ai去水印·石榴智能·自动去水印
JAVA面经实录9171 小时前
RabbitMQ全套学习知识手册
java·rabbitmq
0xDevNull1 小时前
Java实战面试题(一)
java·开发语言
好家伙VCC1 小时前
动态因子图谱+滚动SHAP重构量化模型可解释性
java·人工智能·重构
椰椰椰耶1 小时前
[SpringCloud][11] Nacos 负载均衡,服务下线、权重配置、同集群优先访问
java·spring cloud·负载均衡
Miss roro1 小时前
通用OA能不能替代专业法务系统?钉钉飞书和律杏法务云的实测对比
java·钉钉·飞书·法律科技·企业诉讼管理·法务管理系统
不是光头 强1 小时前
feign-list-param-crash-cpp
java·数据结构·list
Chase_______1 小时前
【Java基础 | 10】异常处理入门:Throwable、try-catch-finally 与异常调用栈一次讲清
java
雪的季节1 小时前
C++ 运行时多态 vs 编译时多态
开发语言