Leetcoder Day10|栈与队列part02(栈的应用)

news2024/11/27 10:38:09

语言:Java/C++ 

目录

20. 有效的括号 

1047. 删除字符串中的所有相邻重复项 

150. 逆波兰表达式求值

今日总结


20. 有效的括号 

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 注意空字符串可被认为是有效字符串。

由于栈的特殊性(FILO),很适合解决对称匹配类问题。括号匹配就是使用栈解决的经典问题。

因为我们的阅读习惯都是从左至右的,所以往往先出现的都是左括号,因此先设置一个匹配栈,用于存放应该与已经出现的左括号所匹配的右括号,并且,先出现的左括号对应的右括号类型往往是后出现的,这个情况非常适合栈的特点,先进后出。如输入的字符串为"{[()]}"第一个出现的是"{"因此我们在栈中存放一个"}",并且它是这个字符串的最后一个字符。因为已经对应左括号将应该出现的右括号都放入栈中了,当遍历到第一个右括号字符时,开始进行出栈操作

遇到匹配问题,首先要进行分类,找出可能出现的情况,对于本题会出现以下三种情况:

  1. 字符串里左方向的括号多余:字符串结束栈还不为空。
  2. 字符串里右方向的括号多余:栈为空时,字符串还没结束。
  3. 字符串里括号没有多余,但是不匹配:遍历字符串时,栈顶右括号与当前字符串所指的字符不匹配。
class Solution {
    public boolean isValid(String s) {
         Stack<Character> stack=new Stack<>(); 
         if(s.length() % 2==1) return false;
         for(int i=0; i<s.length();i++){
             char ch=s.charAt(i);
             //将与左括号匹配的右括号压入栈中
             if (ch=='{') stack.push('}');
             else if(ch=='(') stack.push(')');
             else if(ch=='[') stack.push(']');
             //若栈提前为空或当前字符不等于弹出来的右括号,则返回false
             else if (stack.isEmpty() || stack.peek()!= ch) return false;
             else stack.pop();
         }   
         //若字符串为空栈不为空
         return stack.isEmpty();
    }
}

⚠️ 在进行情况判断的时候,一定要记住是stack.peek()!= ch,而不是stack.pop()!=ch,否则会导致java.util.EmptyStackException 异常。因此已经进行了一次pop操作了。


1047. 删除字符串中的所有相邻重复项 

给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:

  • 输入:"abbaca"
  • 输出:"ca"
  • 解释:例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。

提示:

  • 1 <= S.length <= 20000
  • S 仅由小写英文字母组成。

因为本题涉及两个相邻且相同,转换思路就是,如果字符串里存在对称的结构,我们就会进行删除,实际上跟上一题有效括号匹配的题思路是一样的。只不过在括号里我们要判断的是不匹配的情况,而这里我们要删除匹配的情况因此可以将字符串遍历,先判断再入栈,如果当前字符与栈顶元素相同,则把栈顶元素弹出,如果不等,则放入栈中。随后将栈中剩余的元素依次弹出再把字符串进行翻转返回即可。如果是Java,使用StringBuilder类的reverse()方法来翻转字符串。

⚠️使用栈的用时和内存都较高,因此使用ArrayDeque效率会更高,删除会更快而且节省了翻转操作。

//使用栈
class Solution {
    public String removeDuplicates(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i=0;i<s.length();i++){
             char ch=s.charAt(i);
             if(stack.isEmpty()||stack.peek()!=ch) stack.push(ch);
             else stack.pop();
        }
        s = "";
        while(!stack.isEmpty()){
            s+=stack.pop(); 
        }
        StringBuilder sb = new StringBuilder();
        for(int i=s.length()-1;i>=0;i--){
            sb.append(s.charAt(i));
        }
        return sb.toString();
    }
}

//使用deque

class Solution {
    public String removeDuplicates(String s) {
        ArrayDeque<Character> deque = new ArrayDeque<>();
        for(int i=0;i<s.length();i++){
             char ch=s.charAt(i);
             if(deque.isEmpty()||deque.peek()!=ch) deque.push(ch);
             else deque.pop();
        }
        s = "";
        while(!deque.isEmpty()){
            s+=deque.pollLast();
        }
        return s;
        
    }
}

优化的方法还可以拿字符串直接作为栈,省去了栈还要转为字符串的操作。这样的话设置一个指针top,指向字符串末尾元素,即栈顶。

class Solution {
    public String removeDuplicates(String s) {
        StringBuffer str=new StringBuffer();
        int top=-1; //设置一个指针指向栈顶,即字符串尾部
        for(int i=0;i<s.length();i++){
            char ch=s.charAt(i);
            if(top>=0 && str.charAt(top)==ch){
                str.deleteCharAt(top);
                top--;
            }
            else{
                // 将当前元素接入字符串,top指向最后一个元素
                str.append(ch);
                top++;
            }
        }
        return str.toString();
        
    }
}

150. 逆波兰表达式求值

根据逆波兰表示法,求表达式的值。

逆波兰表达式:是一种后缀表达式,所谓后缀就是指运算符写在后面。

有效的运算符包括 + ,  - ,  * ,  / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

说明:

整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

示例 1:

  • 输入: ["2", "1", "+", "3", " * "]
  • 输出: 9
  • 解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例2:
  • 输入:tokens = ["4","13","5","/","+"]
    输出:6
    解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

逆波兰表达式主要有以下两个优点

  • 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
  • 适合用栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。

根据逆波兰的第二个优点其实本题的做法就已经呼之欲出了,数据结构中,后缀表达式往往可以用后序二叉树展现出来。本题思路可以简化为,遇到一个符号则把符号前面的拿出来进行符号对应的操作再压入栈中,很像上一题相邻重复项的思路,只不过这里的重复项定义为数字。

⚠️本题有几个需要注意的语法事项:

  1. 这里的tokens定义的是数组类型,因此不能用length()方法来提取长度而是使用length
  2. 在进行减法操作时,不能简单的使用deque.pop() - deque.pop(),不然如下图会变成’3-4‘,因为这个是栈,遵守先进后出原则,减数应该在被减数前被弹出来的,所以要用- deque.pop()+deque.pop()才可以表达‘4-3’的结果。

  3. 同理,除法操作也应该注意。
  4. 将数字存入栈时,应该注意转换为整型
class Solution {
    public int evalRPN(String[] tokens) {
        ArrayDeque<Integer> deque=new ArrayDeque<>();
        for (int i = 0; i < tokens.length; i++) {
            String ch = tokens[i];
            if(ch.equals("+")) deque.push(deque.pop() + deque.pop());
            //因为是栈,被减数是在减数后被弹出的
            else if(ch.equals("-")) deque.push(-deque.pop() + deque.pop());
            else if(ch.equals("*")) deque.push(deque.pop() * deque.pop());
            else if(ch.equals("/")) {
                int temp1 = deque.pop();//因为是栈,被除数是在除数后被弹出的
                int temp2 = deque.pop();
                deque.push(temp2 / temp1);
            }
            else deque.push(Integer.valueOf(ch));
        }
        return deque.pop();
    }
}

今日总结

今天主要进行了对栈常规问题的练习,遇到对称消除,对称匹配时,首选栈进行操作,且操作时要注意压入,弹出的顺序,不可搞混。且递归就是用栈来实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1399617.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android双击图片放大移动图中双击点到ImageView区域中心,Kotlin

Android双击图片放大移动图中双击点到ImageView区域中心&#xff0c;Kotlin 初始化状态&#xff0c;ImageView里面只是显示一张fitcenter被缩放的原图&#xff0c;当手指在图片上双击后&#xff08;记录双击点位置&#xff1a;mCurX&#xff0c;mCurY&#xff09;画一个红色小圆…

TensorRT模型优化部署 (八)--模型剪枝Pruning

系列文章目录 第一章 TensorRT优化部署&#xff08;一&#xff09;–TensorRT和ONNX基础 第二章 TensorRT优化部署&#xff08;二&#xff09;–剖析ONNX架构 第三章 TensorRT优化部署&#xff08;三&#xff09;–ONNX注册算子 第四章 TensorRT模型优化部署&#xff08;四&am…

AxiosError: Request failed with status code 503

spring.application.name属性指定了应用程序的名称为ssm_serviceA。这个属性用于标识应用程序&#xff0c;可以在日志、监控和其他相关功能中使用。通常情况下&#xff0c;应用程序的名称是用来区分不同的应用程序或服务的。 通过配置spring.application.name&#xff0c;你可以…

LSTM学习笔记

上一篇文章中我们提到&#xff0c;CRNN模型中用于预测特征序列上下文的模块为双向LSTM模块&#xff0c;本篇中就来针对该模块的结构和实现做一些理解。 Bidirectional LSTM模块结构如下图所示&#xff1a; 在Pytorch中&#xff0c;已经集成了LSTM模块&#xff0c;定义如下&…

Sqoop故障排除指南:处理错误和问题

故障排除是每位数据工程师和分析师在使用Sqoop进行数据传输时都可能遇到的关键任务。Sqoop是一个功能强大的工具&#xff0c;但在实际使用中可能会出现各种错误和问题。本文将提供一个详尽的Sqoop故障排除指南&#xff0c;涵盖常见错误、问题和解决方法&#xff0c;并提供丰富的…

认识并使用Shiro技术

认识并使用Shiro 一、对Shiro的基本认知1、Shiro是什么&#xff1f;2、Shiro的核心组件是&#xff1f;2.1 Subject2.2 UsernamePasswordToken2.3 Realm&#xff08;重点是&#xff1a;AuthorizingRealm用于授权、AuthenticatingRealm用于认证&#xff09;2.4 SecurityManager2.…

NLP论文阅读记录 - 2021 | WOS 基于多头自注意力机制和指针网络的文本摘要

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.问题定义和解决问题的假设问题定义解决问题的假设 三.本文方法3.1 总结为两阶段学习3.1.1 基础系统 3.2 重构文本摘要 四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果4…

面试官:什么是泛型擦除、泛型上界、泛型下界、PECS原则?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 问题1&#xff1a;什么是PECS原则&#xff1f; 说说具体怎么…

回溯法:回溯法通用模版以及模版应用

从一个问题开始 给定两个整数 n 和 k&#xff0c;返回 1 ... n 中所有可能的 k 个数的组合。 示例: 输入: n 4, k 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4] ] 很容易想到 用两个for循环就可以解决。 如果n为100&#xff0c;k为50呢&#xff0c;那就50层for循…

文字的baseLine算法

使用canvas的drawText方法时候&#xff0c;除了要传入画笔和text还需要传入一个x坐标和y坐标。这边的x和y坐标是Baseline的坐标。 public void drawText(NonNull String text, float x, float y, NonNull Paint paint) {super.drawText(text, x, y, paint);} top:是 baseLine到…

微信小程序之WXML 模板语法之数据绑定、事件绑定、wx:if和列表渲染

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

消息中间件之Kafka(二)

1.Kafka线上常见问题 1.1 为什么要对topic下数据进行分区存储? 1.commit log文件会受到所在机器的文件系统大小的限制&#xff0c;分区之后可以将不同的分区放在不同的机器上&#xff0c; 相当于对数据做了分布式存储&#xff0c;理论上一个topic可以处理任意数量的数据2.提…

OpenHarmony 应用开发入门 (二、应用程序包结构理解及Ability的跳转,与Android的对比)

在进行应用开发前&#xff0c;对程序的目录及包结构的理解是有必要的。如果之前有过android开发经验的&#xff0c;会发现OpenHarmony的应用开发也很简单&#xff0c;有很多概念是相似的。下面对比android分析总结下鸿蒙的应用程序包结构&#xff0c;以及鸿蒙对比android的诸多…

【报错】Arco新建工程时 Error: spawnSync pnpm.cmd ENOENT

文章目录 安装环境开始安装选择技术栈选择pro项目遇到的问题 安装步骤&#xff1a;https://arco.design/vue/docs/pro/start 安装环境 npm i -g arco-cli开始安装 arco init hello-arco-pro选择技术栈 ? 请选择你希望使用的技术栈React❯ Vue选择pro项目 ? 请选择一个分类业…

智谱AI发布新一代国产文本生成模型:GLM-4,“宣称”性能逼近GPT-4 (怎么又是GPT )

希望别又是一个只顾着跑分数不注重性能的东西。。。 智谱AI GLM-4介绍体验网址链接&#xff1a;智谱AI开放平台 更多消息&#xff1a;AI人工智能行业动态&#xff0c;aigc应用领域资讯 智谱AI是一家专注于人工智能技术研发和应用的公司&#xff0c;致力于打造全球领先的大模型…

2024年美赛数学建模思路 - 案例:感知机原理剖析及实现

文章目录 1 感知机的直观理解2 感知机的数学角度3 代码实现 4 建模资料 # 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 感知机的直观理解 感知机应该属于机器学习算法中最简单的一种算法&#xff0c;其…

第二课:BERT

文章目录 第二课&#xff1a;BERT1、学习总结&#xff1a;为什么要学习BERT&#xff1f;预训练模型的发展历程BERT结构BERT 输入BERT EmbeddingBERT 模型构建BERT self-attention 层BERT self-attention 输出层BERT feed-forward 层BERT 最后的Add&NormBERT EncoderBERT 输…

深入剖析 Git 对象底层原理

一、引言 在我们日常使用 Git 时&#xff0c;通常的操作是&#xff1a; 在写完一段代码后&#xff0c;执行 git add命令&#xff0c;将这段代码添加到暂存区中然后再执行 git commit和 git push 命令&#xff0c;将 本地 Git 版本库中的提交同步到服务器中的版本库中 Git 在…

phpStorm 设置终端为git bash

环境&#xff1a; windows , PhpStorm 2022 为自己的终端配置git样式的使用&#xff0c; 默认终端样式 一、打开设置&#xff0c;选择git bin 二、重新打开终端 不加--login -i 的终端 加了--login -i 的终端 最重要的一点是什么&#xff0c;他可以像mac一样支持 ctrlv 复…

【学习记录】Ouster雷达运行fastlio提示 Failed to find match for field ‘ring‘ 的解决办法

本文仅用于个人记录。 在使用ouster雷达运行fastlio代码时&#xff0c;提示 Failed to find match for field ‘ring’ 但ouster雷达确实是发布了ring信息&#xff0c;可以从启动的rviz里面看到包括ring。 进一步检查&#xff0c;发现ouster对ring的定义是 uint_16t&#xf…