剑指 Offer II 036. 后缀表达式 / 剑指 Offer II 037. 小行星碰撞 / 剑指 Offer II 038. 每日温度

这篇博客探讨了三种使用栈解决的算法问题:1) 通过栈处理逆波兰表达式求解;2) 实现小行星碰撞模拟,确定幸存行星;3) 利用单调栈计算每日所需等待升至更高温度的天数。这些题目都巧妙地运用了栈的数据结构特性,展示了其在计算和逻辑判断中的高效性。
摘要由CSDN通过智能技术生成

剑指 Offer II 036. 后缀表达式【中等题】

思路:

遍历给定的字符串数组,将数字压入栈,遇到运算符则将栈顶的两个元素弹出进行运算后将结果再压入栈,题目保证给定的逆波兰表达式总是有效的,因此一定可以返回一个有效的答案,因此处理完之后栈中只会剩下最后的答案,将栈顶元素弹出作为答案返回即可。

代码:

class Solution {
    public int evalRPN(String[] tokens) {
        Deque<Integer> deque = new ArrayDeque<>();
        for (String token : tokens) {
            char ch = token.charAt(0);
            switch (ch){
                case '+':
                    //将 + 前边的两个数弹出,相加之后压入栈
                    int n2 = deque.pop(),n1 = deque.pop();
                    deque.push(n1+n2);
                    break;
                case '-':
                    if (token.length() == 1){
                        //将 - 前边的两个数弹出,相减之后入栈
                        int n4 = deque.pop(),n3 = deque.pop();
                        deque.push(n3-n4);
                    }else {
                        //这只是个负数,将其压入栈
                        deque.push(Integer.parseInt(token));
                    }
                    break;
                case '*':
                    //将 * 前边的两个数弹出,相乘之后入栈
                    int a2 = deque.pop(),a1 = deque.pop();
                    deque.push(a1*a2);
                    break;
                case '/':
                    //将 / 前边的两个数弹出,相除之后入栈
                    int a4 = deque.pop(),a3 = deque.pop();
                    deque.push(a3/a4);
                    break;
                default:
                    //这是一个数据,将其转为int类型后压入栈
                    deque.push(Integer.parseInt(token));
            }
        }
        //处理到最后栈中只会剩下一条数据,这就是最终结果,将其弹出返回即可
        return deque.pop();
    }
}

剑指 Offer II 037. 小行星碰撞【中等题】

思路:

从左到右遍历给定的行星数组,将行星压入栈,并判断行星的移动方向,遇见第一个右移的行星,将当前行星下标+1后退出循环。
从第一个右移行星右侧开始继续向右判断,如果待判断行星右移,则将其压入栈继续判断下一个行星,如果待判断行星左移,则将其与栈中的右移行星进行爆炸抵消:那么如何进行抵消呢?如果栈顶的右移行星,如果右移行星质量小于左移行星,则继续尝试取出栈顶的右移行星;如果右移行星质量大于左移行星,则重新将右移行星入栈,退出爆炸循环,继续判断下一个位置的行星;如果右移行星质量等于左移行星,则直接退出爆炸循环,继续判断下一个位置的行星。退出爆炸循环后,此时如果爆炸循环中没有直接退出到外层循环,继续判断下一个位置,那么此时栈顶行星一定是在左移,此时说明这个正在左移的当前行星质量实在太大,将所有的右移行星都炸掉了,此时需要从当前行星开始向右遍历行星数组,并将遍历到的行星入栈,直到重新找到一个右移的行星位置,将行星下标index更新为新的右移行星下标+1
当所有行星遍历完成之后,此时栈中剩下的元素就是幸存的行星,新建一个int类型数组remain,长度等于栈的大小,将栈中的元素倒序取出,正序添加到remain中,返回remain

代码:

class Solution {
    public int[] asteroidCollision(int[] asteroids) {
        int n = asteroids.length;
        Deque<Integer> deque = new ArrayDeque<>();
        int index = 0;
        while (index < n){//寻找第一个右移的行星位置
            int cur  = asteroids[index++];
            deque.push(cur);
            if (cur > 0){
                break;
            }
        }
        while (index < n){
            //获取现在要判断的行星 cur
            int cur = asteroids[index];
            if (cur > 0){//cur行星向右移动,不可能相撞,将其压入栈
                deque.push(cur);
                index++;
            }else {//cur行星向左移动,需要与正在右移的pre行星进行碰撞判断
                //是否判断下一个位置行星的标志位
                boolean flag = false;
                while (!deque.isEmpty() && deque.peek() > 0){
                    //获取现在正在右移的行星 pre
                    int pre = deque.pop();
                    if (pre < -cur){//pre爆炸
                        //正在右移的行星爆炸,左移行星继续碰撞上一个正在右移的行星
                        continue;
                    }
                    if (pre > -cur){//cur爆炸
                        //重新将pre入栈,退出爆炸循环,判断下一个位置的行星
                        deque.push(pre);
                        flag = true;
                        break;
                    }
                    if (pre == -cur){//一起爆炸
                        //直接退出爆炸循环,判断下一个位置的行星
                        flag = true;
                        break;
                    }
                }
                if (flag){//如果flag为true,说明需要判断下一个位置的行星,将index+1后进行下次判断
                    index++;
                    continue;
                }
                //此时栈顶行星正在左移,说明cur将左侧右移的行星全部消灭,将cur入栈之后需要在cur右侧重新寻找第一个右移的行星
                while (index < n){
                    //求出cur右侧的行星
                    cur = asteroids[index++];
                    //将当前行星入栈
                    deque.push(cur);
                    if (cur > 0){//如果行星右移,我们找到了cur右侧第一个右移的行星,退出循环,否则继续寻找下一个右移行星
                        break;
                    }
                }
            }
        }
        int size = deque.size();
        int[] remain = new int[size];
        for (int i = 0; i < size; i++) {//将deque中的元素倒序取出并正序加入remain数组
            remain[i] = deque.removeLast();
        }
        return remain;
    }
}

剑指 Offer II 038. 每日温度【中等题】

思路:【deque单调栈】&【数组模拟单调栈】

思路都是一样的,正向遍历温度数组,当栈为空时将温度对应的下标压入栈,当栈不为空时,判断当前温度与栈顶温度的大小关系,如果小于等于栈顶温度,将当前温度对应的下标压入栈,如果大于栈顶温度,进入出栈循环,将当前栈顶温度对应的下标出栈,设为peak,将needDays数组中栈顶下标位置设置为当前温度i与栈顶温度peak的差,即 needDays[peak] = i - peak,直到当前温度小于等于栈顶温度,或者栈为空时,退出出栈循环。

数组模拟单调栈代码源自官解下边评论区yukiyama

代码1:

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int n = temperatures.length;
        int[] needDays = new int[n];
        Deque<Integer> deque = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {//正向遍历温度数组
            //取出当前遍历到的温度
            int t = temperatures[i];
            //当栈不为空时,且当前温度 比 栈顶温度 大 时
            while (!deque.isEmpty() && t > temperatures[deque.peek()]){
                //取出栈顶温度对应的下标
                int peak = deque.pop();
                //将栈顶温度下标处的needDay数组元素置为 当前下标 - 栈顶下标
                needDays[peak] = i - peak;
            }
            //当前温度小于栈顶元素,或者栈为空时,将当前温度的下标入栈
            deque.push(i);
        }
        return needDays;
    }   
}

代码2:

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int n = temperatures.length,top = -1;
        int[] needDays = new int[n],satck = new int[n];
        for (int i = 0; i < n; i++) {//正向遍历温度数组
            //取出当前遍历到的温度
            int t = temperatures[i];
            //当栈不为空时,且当前温度 比 栈顶温度 大 时
            while (top != -1 && t > temperatures[satck[top]]){
                //取出栈顶温度对应的下标
                int peak = satck[top--];
                //将栈顶温度下标处的needDay数组元素置为 当前下标 - 栈顶下标
                needDays[peak] = i - peak;
            }
            //当前温度小于栈顶元素,或者栈为空时,将当前温度的下标入栈
            satck[++top] = i;
        }
        return needDays;
    }   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值