227 基本计算器 II(栈)

1. 问题描述:

实现一个基本的计算器来计算一个简单的字符串表达式的值。

字符串表达式仅包含非负整数,+, - ,*,/ 四种运算符和空格  。 整数除法仅保留整数部分。

示例 1:

输入: "3+2*2"
输出: 7
示例 2:

输入: " 3/2 "
输出: 1
示例 3:

输入: " 3+5 / 2 "
输出: 5
说明:

你可以假设所给定的表达式都是有效的。
请不要使用内置的库函数 eval。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/basic-calculator-ii

2. 思路分析:

① 对于这道表达式的题目来说,其实就是栈的经典应用,我们可以使用两个栈一个是存放操作符的栈,另外一个是存放数字的栈,对于输入的字符串,如果是空格那么忽略,直接continue,如果是数字那么直接加入到数字栈中,如果是操作符的话,假如栈为空的情况那么直接入栈,假如不为空那么需要判断操作符栈中的栈顶元素与当前的操作符的优先级关系,分为以下两种情况:

1)当前的正在遍历的字符是 * 或者是 / 符号操作符,栈顶元素是+或者是-那么这个时候是遍历的字符的优先级大于了栈顶符号的优先级那么这个时候是直接将操作符入栈即可,继续循环

2)遍历的字符与栈顶字符是同级的情况,比如两个是+ -或者是* / 的情况,或者是栈顶为* / 当前遍历的字符为 + /的情况这个时候优先级都规定为小于

② 对于优先级是小于的情况那么我们需要弹出符号栈中的元素,并且弹出数字栈的两个数字进行运算,并且计算结果存放到数字栈中,然后继续循环,直到当前遍历的操作符优先级大于了栈顶元素的优先级才停止训话,最后将遍历的操作符加入到操作符栈中,举一个例子:1 + 2 * 3 - 4

一开始是1直接进数字栈,第二个是 + 符号栈为空直接进符号栈,第三个是数字直接进数字栈,第四个是*需要判断当前元素的优先级与栈顶元素的优先级这个时候栈顶元素为 +直接入栈,第四个是3直接进数字栈,第六个是-需要判断优先级,栈顶元素为*优先级比较小,弹出栈顶元素*,并且弹出数字栈的两个元素2,3计算得到6进数字栈,继续循环发现是+这个时候优先级还是小于弹出符号,并且弹出两个数字1,6,计算得到7进栈,符号栈为空将 - 进栈,第七个是4进数字栈字符串遍历结束,这样的话操作符栈还有元素,所以最后需要将符号栈的元素弹出来,对数字栈的数字进行运算,将结果进数字栈,最后符号栈为空结束循环,数字栈的栈顶元素就是最终的计算结果,其实这个过程还是很好理解的,最好结合具体的例子这样的话代码还是很容易写出来的,可以看一下后缀表达式是怎么样计算出来的,这个过程就比较清楚了

③ 遇到错误假如是比较难判断出来的,对于java来说,idea的debug调试就显得非常有用了,使用简单的例子执行每一步就很容易发现错误在哪里提高效率,这个比自己在那里检查代码要快,效率要高所以遇到难解决的错误的时候,debug真的是不错的选择,我在刷领扣代码的时候发现还是比较好用的,比较快检查出错误在哪里

3. 代码如下:

import java.util.Scanner;
import java.util.Stack;
public class Solution {
    public int calculate(String s) {
        Stack<Integer> nums = new Stack<>();
        Stack<Character> ops = new Stack<>();
        for (int i = 0; i < s.length(); ++i){
            char c = s.charAt(i);
            if (c == ' ') continue;
            else if (c >= '0' && c <= '9') {
                /*这里可能存在大于等于10的数字*/
                int n = 0;
                while (i < s.length() && c >= '0' && c <= '9'){
                    n = n * 10 + (c - '0');
                    ++i;
                    if (i == s.length())break;
                    c = s.charAt(i);
                }
                //回到上一个位置因为在for循环中还会自增1
                --i;
                nums.add(n);
            }
            else if (ops.isEmpty()) ops.add(c);
            else if (!ops.isEmpty()){
                /*操作符的情况*/
                solve(c, nums, ops);
            }
        }
        /*需要注意这里可能操作符栈还有操作符*/
        while (!ops.isEmpty() && !nums.isEmpty()){
            char c = ops.pop();
            int num1 = nums.pop();
            int num2 = nums.pop();
            nums.add(cal(c, num2, num1));
        }
        return nums.peek();
    }

    private void solve(char c, Stack<Integer> nums, Stack<Character> ops) {
        /*进行符号的处理判断站定元素与当前元素的优先级然后进行处理*/
        if (prior(c, ops)){
            /*当当前符号的优先级优于栈顶符号的时候直接进栈*/
            ops.add(c);
            return;
        }
        while (!ops.isEmpty() && !prior(c, ops)){
            /*弹出操作数进行运算*/
            char curops = ops.pop();
            int num1 = nums.pop();
            int num2 = nums.pop();
            int res = cal(curops, num2, num1);
            nums.add(res);
        }
        /*将最后的操作符进栈*/
        ops.add(c);
    }

    private int cal(char curops, int num1, int num2) {
        if (curops == '+') return  num1 + num2;
        else if (curops == '-') return  num1 - num2;
        else if (curops == '*') return  num1 * num2;
        return  num1 / num2;
    }

    private boolean prior(char c, Stack<Character> ops) {
        char peek = ops.peek();
        if ((c == '*' || c == '/') && (peek == '+' || peek == '-')) return true;
        return false;
    }
}
发布了569 篇原创文章 · 获赞 153 · 访问量 59万+

猜你喜欢

转载自blog.csdn.net/qq_39445165/article/details/105209233