IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> LeetCode_Stack_227. Basic Calculator II 基本计算器 II(Java)【栈,字符串处理】 -> 正文阅读

[数据结构与算法]LeetCode_Stack_227. Basic Calculator II 基本计算器 II(Java)【栈,字符串处理】

目录

一,题目描述

英文描述

中文描述

示例与说明

二,解题思路

三,AC代码

Java

四,解题过程

第一博

第二搏


一,题目描述

英文描述

Given a string s which represents an expression, evaluate this expression and return its value.?

The integer division should truncate toward zero.

You may assume that the given expression is always valid. All intermediate results will be in the range of [-231, 231 - 1].

Note: You are not allowed to use any built-in function which evaluates strings as mathematical expressions, such as eval().

中文描述

给你一个字符串表达式?s?,请你实现一个基本计算器来计算并返回它的值。

整数除法仅保留整数部分。

示例与说明

?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/basic-calculator-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二,解题思路

参考@宫水三叶【使用「双栈」解决「究极表达式计算」问题】

这个题解描述的非常详细,还包含了其他关于表达式求解题目的扩展计算,关键部分如下方截图:

?


针对本题(表达式中所有整数为非负整数,也就是第一个数不可能为负。而且只有两种优先级的操作符,没有左右括号)有一个简单的方法:记录前一个操作符preOperation(该方法在上述题解的评论区中)

比如2+3*4/2-1,为了方便处理结尾,可以在表达式后加0即2+3*4/2-1+0,每遇到一个操作符时可以获得以下信息:当前操作符,前一个操作符preOperation,前一个操作符两边的操作数(一个在栈顶,一个是当前数字)。根据操作符进行不同的处理

        for (char c : s.toCharArray()) {
            if (c == ' ') continue;
            if (Character.isDigit(c)) {
                num = num * 10 + (c-'0');
            } else {
                switch (preOperation) {
                    case '+': stack.push(num); break;
                    case '-': stack.push(-1 * num); break;
                    case '*': stack.push(stack.pop() * num); break;
                    case '/': stack.push(stack.pop() / num); break;
                    default:
                }
                preOperation = c;
                num = 0;
            }
        }

循环结束,操作数栈内只剩下需要加减的元素,全部相加即可

return stack.stream().mapToInt(Integer::intValue).sum();

三,AC代码

Java

详细版

class Solution {
    // 使用 map 维护一个运算符优先级
    // 这里的优先级划分按照「数学」进行划分即可
    Map<Character, Integer> map = new HashMap<>(){{
        put('-', 1);
        put('+', 1);
        put('*', 2);
        put('/', 2);
        put('%', 2);
        put('^', 3);
    }};
    public int calculate(String s) {
        // 将所有的空格去掉
        s = s.replaceAll(" ", "");
        char[] cs = s.toCharArray();
        int n = s.length();
        // 存放所有的数字
        Deque<Integer> nums = new ArrayDeque<>();
        // 为了防止第一个数为负数,先往 nums 加个 0
        nums.addLast(0);
        // 存放所有「非数字以外」的操作
        Deque<Character> ops = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            char c = cs[i];
            if (c == '(') {
                ops.addLast(c);
            } else if (c == ')') {
                // 计算到最近一个左括号为止
                while (!ops.isEmpty()) {
                    if (ops.peekLast() != '(') {
                        calc(nums, ops);
                    } else {
                        ops.pollLast();
                        break;
                    }
                }
            } else {
                if (isNumber(c)) {
                    int u = 0;
                    int j = i;
                    // 将从 i 位置开始后面的连续数字整体取出,加入 nums
                    while (j < n && isNumber(cs[j])) u = u * 10 + (cs[j++] - '0');
                    nums.addLast(u);
                    i = j - 1;
                } else {
                    if (i > 0 && (cs[i - 1] == '(' || cs[i - 1] == '+' || cs[i - 1] == '-')) {
                        nums.addLast(0);
                    }
                    // 有一个新操作要入栈时,先把栈内可以算的都算了 
                    // 只有满足「栈内运算符」比「当前运算符」优先级高/同等,才进行运算
                    while (!ops.isEmpty() && ops.peekLast() != '(') {
                        char prev = ops.peekLast();
                        if (map.get(prev) >= map.get(c)) {
                            calc(nums, ops);
                        } else {
                            break;
                        }
                    }
                    ops.addLast(c);
                }
            }
        }
        // 将剩余的计算完
        while (!ops.isEmpty()) calc(nums, ops);
        return nums.peekLast();
    }
    void calc(Deque<Integer> nums, Deque<Character> ops) {
        if (nums.isEmpty() || nums.size() < 2) return;
        if (ops.isEmpty()) return;
        int b = nums.pollLast(), a = nums.pollLast();
        char op = ops.pollLast();
        int ans = 0;
        if (op == '+') ans = a + b;
        else if (op == '-') ans = a - b;
        else if (op == '*') ans = a * b;
        else if (op == '/')  ans = a / b;
        else if (op == '^') ans = (int)Math.pow(a, b);
        else if (op == '%') ans = a % b;
        nums.addLast(ans);
    }
    boolean isNumber(char c) {
        return Character.isDigit(c);
    }
}

作者:AC_OIer
链接:https://leetcode-cn.com/problems/basic-calculator-ii/solution/shi-yong-shuang-zhan-jie-jue-jiu-ji-biao-c65k/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

简单版

    public int calculate(String s) {
        s = s + "+0";
        char preOperation = '+';
        int num = 0;
        Stack<Integer> stack = new Stack<>();
        for (char c : s.toCharArray()) {
            if (c == ' ') continue;
            if (Character.isDigit(c)) {
                num = num * 10 + (c-'0');
            } else {
                switch (preOperation) {
                    case '+': stack.push(num); break;
                    case '-': stack.push(-1 * num); break;
                    case '*': stack.push(stack.pop() * num); break;
                    case '/': stack.push(stack.pop() / num); break;
                    default:
                }
                preOperation = c;
                num = 0;
            }
        }
        return stack.stream().mapToInt(Integer::intValue).sum();
    }

四,解题过程

第一博

时间隔得久了,原以为能轻松拿下的,结果一晚上都卡在这里了。。。

还写下了下面屎山一样的代码,最重要的是结果还是错的。。。

错误原因是算法思路有问题:遇到低优先级运算符时,将操作数栈内的高优先级操作符逐个弹出计算,最后栈内只剩低优先级操作符,重新遍历一遍操作数栈计算即可。

这样就会有一种倒着计算的感觉,比如1+2*3/2*3-2,在计算-2时,依次计算2*3=6、3/6=0、2*0=0.(从根本逻辑上就出错了)

代码贴出来以示警告o( ̄┰ ̄*)ゞ

// 这是错误的代码!!!
class Solution {
    public int calculate(String s) {
        int ans = 0;
        StringBuilder tem = new StringBuilder();
        Deque<Integer> num = new LinkedList<>();
        Deque<Character> operator = new LinkedList<>();

        String S = s.concat("@");// 设置虚拟操作符 优先级和+ -相同
        // System.out.println(S);
        for (int i = 0; i < S.length(); i++ ) {
            if (S.charAt(i) == ' ') continue;
            // 这种方法拼接效率太低了 建议使用num = num * 10 + (c-'0')来获取操作符
            if (S.charAt(i) >= '0' && S.charAt(i) <= '9') {
                tem.append(Character.toString(S.charAt(i)));
                continue;
            }
            num.push(Integer.parseInt(tem.toString()));
            // System.out.println(num);
            // System.out.println(operator);
            tem = new StringBuilder();
            switch(S.charAt(i)) {
                case '+':
                case '-':
                case '@':
                    while (!operator.isEmpty() && (operator.peek() == '*' || operator.peek() == '/')) {
                        // 注意顺序:先弹出的是操作数b 然后才是a
                        int b = num.pop();
                        int a = num.pop();
                        if (operator.peek() == '*') num.push(a * b);
                        else if (operator.peek() == '/') num.push(a / b);
                        operator.pop();
                    }
                    operator.push(S.charAt(i));
                    break;
                case '*':
                case '/':
                    operator.push(S.charAt(i));
                    break;

            }
        }
        // System.out.println(num);
        // System.out.println(operator);
        operator.pop();// 弹出设置的虚拟操作符
        // System.out.println(num);
        // System.out.println(operator);
        while (!operator.isEmpty()) {
            System.out.println(num);
        System.out.println(operator);
            // 注意顺序:从栈底向栈顶逐个进行运算(比如1-2+3,正确结果应该为2,但仍按照栈的操作来就是2+3=5,然后1-5=-4)
            // 先弹出的是操作数b 然后才是a
            int a = num.removeLast();
            int b = num.removeLast();
            // System.out.println(a);
            // System.out.println(b);
            if (operator.getLast() == '+') num.addLast(a + b);
            else if (operator.getLast() == '-') num.addLast(a - b);
            // else if (operator.peek() == '*') num.push(a * b);
            // else if (operator.peek() == '/') num.push(a / b);
            operator.removeLast();
        }
        return num.peek();
    }
}

第二搏

参考大佬的解法,这一题果然不简单。。。(简单版代码执行结果?

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-22 13:45:16  更:2021-08-22 13:47:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:29:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码