栈与计算—— 150、227、224※

150. 逆波兰表达式求值(中等)

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

备注:向零截断是一种取整方式,‌也称为截断取整。‌这种取整方法将一个浮点数取整为最接近但小于它的整数。‌具体来说,‌对于正数,‌向零截断会取其整数部分;‌对于负数,‌向零截断会取其绝对值的整数部分并添加负号。‌例如,‌17 / 10 = 1,‌5 / 2 = 2,‌而 -9 / 4 = -2。

解法一、双向队列模拟栈

 双向队列相关写在碎碎念里了,然后发现不用default,可以用isNumber判别

class Solution {
    public static int evalRPN(String[] tokens) {
        Deque<Integer> num = new ArrayDeque<>();
        for(String s : tokens){
            int len = num.size();
            int a,b;
            switch (s){
                case "+":
                    a = num.removeLast();//第一个
                    b = num.removeLast();//第二个
                    num.add(a+b);
                    break;
                case "-":
                    a = num.removeLast();//第一个
                    b = num.removeLast();//第二个
                    num.add(b-a);
                    break;
                case"/":
                    a = num.removeLast();//第一个
                    b = num.removeLast();//第二个
                    num.add(b/a);
                    break;
                case"*":
                    a = num.removeLast();//第一个
                    b = num.removeLast();//第二个
                    num.add(b*a);
                    break;
                default:
                    int t = Integer.parseInt(s);
                    num.add(t);
                    break;
            }
        }
        return num.pop();
    }
}

227. 基本计算器 II(中等)

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

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

你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。

注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。

解法一、栈

这里不用if else结构是因为需要判断那个i==n-1,如果最后一个是数字,它依旧要考虑操作符号。

大体:对于第一个数字,默认的op是‘+’,对于其他的,可以用preSign记录下来。如果是数字,则不断循环,处理num值。如果不是数字或者是最后一个数字,则考虑操作符。这里不需要考虑空格,把空格跳掉即可,空格只是干扰项。

说起来这个A&&B||C的结构也很神奇,等效于(A&&B)||C,原来&和|是有优先级区分的(没细想过这个问题)

class Solution {
    public static int calculate(String s) {
        Deque<Integer> stack = new ArrayDeque<Integer>();
        char preSign = '+';
        int num = 0;
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            if (Character.isDigit(s.charAt(i))) {
                num = num * 10 + s.charAt(i) - '0';
            }
            if (!Character.isDigit(s.charAt(i)) && s.charAt(i) != ' ' || i == n - 1) {
                switch (preSign) {
                    case '+':
                        stack.push(num);
                        break;
                    case '-':
                        stack.push(-num);
                        break;
                    case '*':
                        stack.push(stack.pop() * num);
                        break;
                    default:
                        stack.push(stack.pop() / num);
                }
                preSign = s.charAt(i);
                num = 0;
            }
        }
        int ans = 0;
        while (!stack.isEmpty()) {
            ans += stack.pop();
        }
        return ans;
    }
}

 

解法二、模拟

评论区看来的~↓

用last巧妙地记录和模拟了栈顶结构。

. - 力扣(LeetCode)

class Solution {
public:
    int calculate(string s) {
        int ret = 0, last = 0;
        int value = 0;
        char op = '+';
        s += "+";
        for(auto &c:s) {
            if(isdigit(c))
                value = value * 10 + (c - '0');
            else if(c != ' ') {
                if(op == '+') {
                    ret += value;
                    last = value;
                }else if(op == '-') {
                    ret -= value;
                    last = -value;
                }else if(op == '*') {
                    ret = ret - last + value * last;
                    last = value * last;
                }else {
                    ret = ret - last + last/value;
                    last = last/value; 
                }
                op = c;
                value = 0;
            }
        }
        return ret;
    }
};

224. 基本计算器(困难) 

 

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

注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。

示例 1:

输入:s = "1 + 1"
输出:2

示例 2:

输入:s = " 2-1 + 2 "
输出:3

示例 3:

输入:s = "(1+(4+5+2)-3)+(6+8)"
输出:23

解法一、栈+模拟 

num存储数字,preOp参考227,i因为while是i++判断所以从-1开始,ops记录层数,默认一层为1,遇到(则push,遇到)则pop。因为只有加减,所以用1、-1即可

三个if(其中一个是if-else)的顺序很重要,第一个决定数字,第二个决定加减,第三个决定括号栈

易错点:①res的处理②preOp的设置③括号时ops的设置④左括号时把preOp置1

class Solution {
    public static int calculate(String s) {
        Deque<Integer> ops = new ArrayDeque<>();
        int res = 0, num = 0, preOp = 1;
        int i = -1, len = s.length();
        ops.push(1);

        //单指针循环遍历
        while (++i < len) {
            if (Character.isDigit(s.charAt(i))) {
                num = num * 10 - '0' + s.charAt(i);
            }
            if (s.charAt(i) == '+' || s.charAt(i) == '-' || s.charAt(i) == ')'|| i == len-1 ) {
                res += num * preOp * ops.element();
                if (s.charAt(i) == '+') preOp = 1;
                else preOp = -1;
                num = 0;
            }
            if (s.charAt(i) == '(') {;
                ops.push(ops.element() * preOp);
                preOp = 1;
            } else if (s.charAt(i) == ')') {
                ops.pop();
            }
        }
        return res;
    }
}

 

解法二、改进版

空格跳过,处理数字,处理符号,清晰易懂。无论哪种做法,都要记得一开始push一个1的默认值,当作全部表达式最外层套了个()处理

class Solution {
public:
    int calculate(string s) {
        stack<char> st; // 存储正负号
        int ans = 0, num = 0, op = 1;
        st.push(op);

        for (char c : s) {
            if (c == ' ') continue;
            else if (c >= '0') num = num * 10 - '0' + c;
            else {
                ans += op * num;
                num = 0;

                if (c == '+') op = st.top();
                else if (c == '-') op = -st.top();
                else if (c == '(') st.push(op); // 将括号前符号放入栈顶
                else st.pop();
            }
        }

        return ans + op * num;
    }
};

 


碎碎念:

  • 理解了这里用到的双向队列是ArrayDeque,头是0,尾/最后是末端(序号较大处)。push是从头(0)开始加,add是从尾开始加,和stack是有差别的。稍微地熟悉了element/peek之类的差别
  • 150简单使用,227稍微有些复杂(中途会错意了),224注意一下脉络和思路再写会好很多,这个需要复刷
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值