数据结构(Java):力扣Stack集合OJ题

news2024/11/13 14:38:25

1、括号匹配问题

. - 力扣(LeetCode)

1.1 思路分析

根据栈的先进后出原则,我们可以这样解决问题:

遍历字符串,遇见左括号就将左括号push入栈;遇见右括号就pop出栈,将出栈的元素和该右括号比较是否匹配,若匹配则继续遍历并比较,若不匹配则直接返回false。细分为以下几种情况:

1.匹配(左右括号数量相同且匹配):字符串遍历完,且栈为空(右括号与左括号数量相等,且均匹配),则说明括号匹配,返回true。

2.不匹配(括号不匹配):遍历到的右括号和出栈的左括号比较是否匹配,一旦不匹配,立即返回false。

3.不匹配(左括号数量多):当字符串遍历完后,发现栈还不为空,则说明左括号多,不匹配。

4.不匹配(右括号多):遍历遇见右括号需将栈顶的左括号出栈,若要出栈时栈为空,则说明右括号多,不匹配。

1.2 代码

public boolean isValid(String s) {
        //利用栈先进后出特点 解决问题
        Stack<Character> stack = new Stack<>();
        //遍历字符串
        for(int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            
            //若为左括号 将括号入栈
            if(ch == '(' || ch == '{' || ch == '[') {
                stack.push(ch);
            }else {//遍历到的为右括号 进入else
                
                //若栈为空 则说明右括号多 立即返回false
                if(stack.isEmpty()) {
                    return false;
                }
                //若栈不为空 则pop出栈 比较是否匹配 
                char ch2 = stack.pop();
                switch(ch) {//使用switch语句比较是否匹配 一旦不匹配 立即返回false
                    case ')':
                        if(ch2 != '(') {
                            return false;
                        }
                        break;
                    case ']':
                        if(ch2 != '[') {
                            return false;
                        }
                        break;
                    case '}':
                        if(ch2 != '{') {
                            return false;
                        }
                        break;
                }
            }
        }
        //遍历完成且栈为空 则说明匹配 
        if(!stack.isEmpty()) {
            return false;
        }
        return true;
    }

2、栈的弹出、压入序列

2.1 思路分析

以i遍历pushV,每次都将将i下标的元素入栈,再将栈顶元素和j下标元素比较,
若相等:则出栈,j++,i++
不相等:则i++,j保持原位

注意:j++后,j下标与栈顶元素可能依然相等,此时要连续出栈。即j变化后,要继续和栈顶元素比较。

  • i遍历完成,且j也遍历也完成(此时栈肯定为空),说明出栈序列匹配
  • 若i遍历完成后,j还没有遍历完成(栈不为空),则说明出栈序列不匹配
    因为只有栈顶元素和j下标元素相等时,才会出栈,j++

 2.2 代码

public boolean IsPopOrder (int[] pushV, int[] popV) {
        Stack<Integer> stack = new Stack<>();
        int j = 0;
        for (int i = 0; i < pushV.length; i++) {
            //每次循环都会将pushV中i下标的元素入栈
            stack.push(pushV[i]);
            //因为j++后,元素可能连续出栈,所以要while循环
            //出栈后,栈可能出现空的情况,!stack.isEmpty(),防止出现空指针异常
            while (!stack.isEmpty() && stack.peek() == popV[j]) {
                j++;
                //若j下标和栈顶元素相同,则出栈
                stack.pop();
            }
        }
        
        //i遍历完成,若此时j也遍历完成(j == popV.length),则说明出栈序列匹配
        return j == popV.length;
    }

3、逆波兰表达式(后缀表达式)求值

. - 力扣(LeetCode)

3.1 逆波兰表达式的定义

逆波兰表达式,也称为后缀表达式,是一种表达式的表示方法,其中运算符位于操作数之后。

后缀表达式由中缀表达式转化而来,可以实现表达式的求值和计算,提高了计算机内存访问的效率。而中缀表达式就是我们平时做运算的表达式。

那么如何将中缀表达式转换为后缀表达式?

  1. 从左向右,以先乘除后加减的次序加括号
  2. 将括号中的相邻两项的运算符拿到括号的后面
  3. 去掉所有括号

 3.2 后缀表达式如何求值(思路分析)

我们拿到后缀表达式后,

  1. 遍历表达式,若是非操作符元素(数字元素),则入栈
  2. 若遇到操作符元素,则出栈两次,将第一次出栈的元素val2作为该操作符的右操作数,将第二次出栈的元素val1作为该操作符的左操作数,接着将所得结果入栈。
  3. 继续遍历,并重复以上操作
  4. 遍历完成后,栈中只剩一个元素,该元素就是后缀表达式的值。

 3.3 代码

class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < tokens.length; i++) {
            String str = tokens[i];

            if (!isOperator(str)) {
                //如果不是是操作符
                //则元素入栈
                int val = Integer.parseInt(str);//将字符串转化为整型
                stack.push(val);
            } else {
                //如果是操作符
                //则弹出栈顶两个元素
                //计算结果,并将结果入栈
                int val2 = stack.pop();
                int val1 = stack.pop();
                if (str.equals("+")) {
                    stack.push(val1 + val2);
                }
                if (str.equals("-")) {
                    stack.push(val1 - val2);
                }
                if (str.equals("*")) {
                    stack.push(val1 * val2);
                }
                if (str.equals("/")) {
                    stack.push(val1 / val2);
                }
            }
        }
        //遍历完成后,栈中还有一个元素
        //该元素就是后缀表达式的值
        return stack.pop();
    }

    //判断该元素是否为操作符
    private boolean isOperator(String str) {
        if (str.equals("+") || str.equals("-")
                || str.equals("*") || str.equals("/")) {
            return true;
        }
        return false;
    }
}

4、最小栈

. - 力扣(LeetCode)

4.1 思路分析

题目要求我们在O(1)内找到栈中的最小值,

而在Java已有的一个栈中我们只能通过遍历找最小值,时间复杂度为为O(n) 。

所以,我们可以建立两个栈,一个栈dataStack用来存储元素,另一个栈minStack的栈顶存最小值。

  1. minStack栈顶存储最小值数据 每次dataStack添加新数据时,和minStack栈顶元素比较,若<= ,则push入栈(一定要 <= ,因为dataStack中可能有多个相同的最小值,保证pop一次后,minStack依然存储着最小值)
  2. 当minStack为空时,那么dataStack添加的元素(第一次入栈的元素)一定为最小值
  3. 当dataStack弹出元素时,我们需要判断这个元素是否为minStack的栈顶元素(最小值),若是,也需要弹出minStack的元素

也就是说, minStack的栈顶元素,就是dataStack的最小值。

4.2 代码

class MinStack {
    Stack<Integer> dataStack;//存储所有数据
    Stack<Integer> minStack;// 栈顶存储最小值数据 每次添加新数据时,和minStack栈顶元素比较,若<= ,则push进minStack

    public MinStack() {
        dataStack = new Stack<>();
        minStack = new Stack<>();
    }

    public void push(int val) {
        dataStack.push(val);
        if (minStack.isEmpty()) {
            // 当minStack为空时,直接push进minStack
            minStack.push(val);
        } else {// 一定要有else 否则,minStack空时,同一个元素会在minStack中push两次
            if (val <= minStack.peek()) {
                // 一定要 <= ,因为dataStack中可能有多个相同的最小值,保证pop一次,minStack依然存储着最小值
                minStack.push(val);
            }
        }
    }

    public void pop() {
        // 操作总是在 非空栈 上调用
        int val = dataStack.pop();
        // 当dataStack栈顶元素为最小值时,也要弹出minStack的栈顶元素
        if (val == minStack.peek()) {
            minStack.pop();
        }
    }

    public int top() {
        return dataStack.peek();
    }

    public int getMin() {
        // minStack的栈顶元素即为最小值
        return minStack.peek();
    }
}

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

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

相关文章

JDK14新特征最全详解

JDK 14一共发行了16个JEP(JDK Enhancement Proposals&#xff0c;JDK 增强提案)&#xff0c;筛选出JDK 14新特性。 - 343: 打包工具 (Incubator) - 345: G1的NUMA内存分配优化 - 349: JFR事件流 - 352: 非原子性的字节缓冲区映射 - 358: 友好的空指针异常 - 359: Records…

游戏的无边框模式是什么?有啥用?

现在很多游戏的显示设置中&#xff0c;都有个比较特殊的选项“无边框”。小伙伴们如果尝试过&#xff0c;就会发现这个效果和全屏几乎一毛一样&#xff0c;于是就很欢快地用了起来&#xff0c;不过大家也许会发现&#xff0c;怎么和全屏比起来&#xff0c;似乎有点不够爽快&…

单例模式Singleton

设计模式 23种设计模式 Singleton 所谓类的单例设计模式&#xff0c;就是采取一定的方法保证在整个的软件系统中&#xff0c;对某个类只能存在一个对象实例&#xff0c;并且该类只提供一个取得其对象实例的方法。 饿汉式 public class BankTest {public static void main(…

[图解]SysML和EA建模住宅安全系统-14-黑盒系统规约

1 00:00:02,320 --> 00:00:07,610 接下来&#xff0c;我们看下一步指定黑盒系统需求 2 00:00:08,790 --> 00:00:10,490 就是说&#xff0c;把这个系统 3 00:00:11,880 --> 00:00:15,810 我们的目标系统&#xff0c;ESS&#xff0c;看成黑盒 4 00:00:18,030 --> …

Kafka基础入门篇(深度好文)

Kafka简介 Kafka 是一个高吞吐量的分布式的基于发布/订阅模式的消息队列&#xff08;Message Queue&#xff09;&#xff0c;主要应用与大数据实时处理领域。 1. 以时间复杂度为O(1)的方式提供消息持久化能力。 2. 高吞吐率。&#xff08;Kafka 的吞吐量是MySQL 吞吐量的30…

数据结构初阶(C语言)-复杂度的介绍

在学习顺序表之前&#xff0c;我们需要先了解下什么是复杂度&#xff1a; 一&#xff0c;复杂度的概念 我们在进行代码的写作时&#xff0c;通常需要用到许多算法&#xff0c;而这些算法又有优劣之分&#xff0c;区分算法的优劣则是通过算法的时间复杂度和空间复杂度来决定。 …

【眼疾病识别】图像识别+深度学习技术+人工智能+卷积神经网络算法+计算机课设+Python+TensorFlow

一、项目介绍 眼疾识别系统&#xff0c;使用Python作为主要编程语言进行开发&#xff0c;基于深度学习等技术使用TensorFlow搭建ResNet50卷积神经网络算法&#xff0c;通过对眼疾图片4种数据集进行训练&#xff08;‘白内障’, ‘糖尿病性视网膜病变’, ‘青光眼’, ‘正常’&…

Python+wxauto=微信自动化?

Pythonwxauto微信自动化&#xff1f; 一、wxauto库简介 1.什么是wxauto库 wxauto是一个基于UIAutomation的开源Python微信自动化库。它旨在帮助用户通过编写Python脚本&#xff0c;轻松实现对微信客户端的自动化操作&#xff0c;从而提升效率并满足个性化需求。这一工具的出现&…

SAP PP学习笔记26 - User Status(用户状态)的实例,订单分割中的重要概念 成本收集器,Confirmation(报工)的概述

上面两章讲了生产订单的创建以及生产订单的相关内容。 SAP PP学习笔记24 - 生产订单&#xff08;制造指图&#xff09;的创建_sap 工程外注-CSDN博客 SAP PP学习笔记25 - 生产订单的状态管理(System Status(系统状态)/User Status(用户状态)),物料的可用性检查&#xff0c;生…

语音识别概述

语音识别概述 一.什么是语音&#xff1f; 语音是语言的声学表现形式&#xff0c;是人类自然的交流工具。 图片来源&#xff1a;https://www.shenlanxueyuan.com/course/381 二.语音识别的定义 语音识别&#xff08;Automatic Speech Recognition, ASR 或 Speech to Text, ST…

数字探秘:用神经网络解密MNIST数据集中的数字!

用神经网络解密MNIST数据集中的数字&#xff01; 一. 介绍1.1 MNIST数据集简介1.2 MLP&#xff08;多层感知器&#xff09;模型介绍1.3 目标&#xff1a;使用MLP模型对MNIST数据集中的0-9数字进行分类 二.数据预处理2.1 数据集的获取与加载2.2 数据集的探索性分析&#xff08;E…

编写商品列表和商品编辑和商品新增页面

addvue <template><!-- 传过来的id --> <!-- {{ $route.query.id }} --> <el-formref"FormRef"style"max-width: 600px":model"FormData":rule"rules"status-iconlabel-width"auto"class"demo-r…

【中台】数字中台建设方案(PPT)

数字中台建设要点&#xff1a; 数据采集与整合&#xff1a; 打破企业内部各个业务系统的数据隔阂&#xff0c;通过数据采集和数据交换实现数据的集中管理&#xff0c;形成统一的数据中心&#xff0c;为后续数据价值的挖掘提供基础。 利用自研或第三方ETL&#xff08;Extract, T…

最长下降序列

如何理解这个题目呢,我们可以每个人的分数放到排名上&#xff0c;然后求解最长下降序列即可 #include<bits/stdc.h> using namespace std;int n; const int N (int)1e5 5; int a[N]; int b[N]; int d[N]; int dp[N]; int t;int main() {cin >> t;while (t--) {…

排序——归并排序及排序章节总结

前面的文章中 我们详细介绍了排序的概念&#xff0c;插入排序&#xff0c;交换排序与选择排序&#xff0c;大家可以通过下面的链接再去学习&#xff1a; ​​​​​​排序的概念及插入排序 交换排序 选择排序 这篇文章就详细介绍一下另一种排序算法&#xff1a;归并排序以及…

PE文件(十)重定位表

重定位表的引入 程序加载过程 在win32下&#xff0c;每一个PE文件&#xff08;其可能由多个子PE文件组成&#xff09;在运行时&#xff0c;操作系统会给分配一个独立的4GB虚拟内存&#xff0c;内存地址从0x00000000到0xFFFFFFFF。其中低2G为用户程序空间&#xff0c;高2G为操…

【Linux】进程间通信——消息队列和信号量

目录 消息队列&#xff08;message queue&#xff09; 信号量&#xff08;Semaphore&#xff09; system V版本的进程间通信方式有三种&#xff1a;共享内存&#xff0c;消息队列和信号量。之前我们已经说了共享内存&#xff0c;那么我们来看一下消息队列和信号量以及它们之间…

【鸿蒙学习笔记】位置设置・position・绝对定位

官方文档&#xff1a;位置设置 目录标题 position&#xff1a;绝对定位&#xff0c;确定子组件相对父组件的位置。 position&#xff1a;绝对定位&#xff0c;确定子组件相对父组件的位置。 正→ ↓ Entry Component struct Loc_position {State message: string Hello Wor…

汇编语言程序设计-8-汇编语言快速查阅

8. 汇编语言快速查阅 文章目录 8. 汇编语言快速查阅常用资料寄存器含义标志寄存器的含义Debug的使用汇编语法 本章列出一些需要经常查阅的知识点。 常用资料 参考视频&#xff1a;烟台大学贺利坚老师的网课《汇编语言程序设计系列专题》&#xff0c;或者是B站《汇编语言程序设计…