【数据结构与算法】栈与队列相关算法的实现

news2024/11/27 5:33:49

目录

检查括号是否成对出现

反转字符串

循环队列的实现

使用队列实现栈

使用栈实现队列


检查括号是否成对出现

算法要求

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

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

比如: "()"、"()[]{}"、"{[]}" 都是有效字符串,而 "(]" 、"([)]" 则不是 

解题思路     

1、我们可以通过一个HashMap来存放所有括号类型,右括号为键,左括号为值。

2、遍历字符串,如果是左括号就入栈,右括号则和栈顶元素作比较,如果刚好形成一对完成括号,则继续。否则说明不是一对完整括号。

3、遍历结束后判断栈中元素是否全部取出,只有全部取出,说明这个字符串中符号成对出现。

    /**
     * 判断这个符号字符串中符号是否成对出现
     * @param s
     * @return
     */
    public static boolean isValid(String s){
        //创建一个hashMap把所有符号都存入
        Map<Character,Character> maps =new HashMap<>();
        maps.put(')','(');
        maps.put(']','[');
        maps.put('}','{');

        Stack<Character> stack =new Stack<>();
        //将字符串转换为字符数组
        char[] chars= s.toCharArray();
        //遍历字符数组
        for (int i = 0; i <chars.length ; i++) {
            //判断这个符号是否为右括号
            if (maps.containsKey(chars[i])){
                //栈中如果为空赋值为#否则取出栈顶元素
                char isEmpty =stack.isEmpty()?'#':stack.pop();
                //判断这个右括号对应的左括号是否等于栈顶元素
                if (isEmpty!=maps.get(chars[i])){
                    return false;
                }
            }else {
                //如果为左括号则入栈
                stack.push(chars[i]);
            }
        }
        //遍历结束 如果栈中还有元素 则说明其中没有对应括号
        return stack.isEmpty();
    }

测试

    public static void main(String[] args) {
        System.out.println("[]{}()中符号是否成对出现:"+isValid("[]{}()"));
        System.out.println("{([})}中符号是否成对出现:"+isValid("{([])}"));
        System.out.println("([)]中符号是否成对出现:"+isValid("([)]"));
        System.out.println("(()中符号是否成对出现:"+isValid("(()"));
    }

测试结果


反转字符串

这个就直接运用栈的后进先出原则,把字符串依次入栈再出栈就行。

   /**
    * 字符串的反转
    * @param s
    * @return
    */   
    public static String stringReversal(String s){
        Stack<Character> stack =new Stack<>();
        for (int i =0;i<s.length();i++){
            stack.push(s.charAt(i));
        }
        String news="";
        for (int i = 0, len = stack.size(); i < len; i++) {
            news+=stack.pop();
        }
        return news;
    }

测试

    public static void main(String[] args) {
        String ts ="the shy";
        String yskm ="you should know me";
        System.out.println("ts反转前:"+ts);
        System.out.println("ts反转后:"+stringReversal(ts));
        System.out.println("yskm反转前:"+yskm);
        System.out.println("yskm反转后:"+stringReversal(yskm));

    }

测试结果


循环队列的实现

和队列相比,循环队列的优点就是不会造成假溢出,因为当队尾到达数组的末尾时,如果数组头部还有空间,则会继续向头部移动。会形成一个循环,除非队尾与队头相邻,则队列才满。

/**
 * 循环队列的实现
 * @author CC
 * @version 1.0
 * @since2023/9/28
 */
public class CircularQueue {
    private int[] array;//使用数组来存储
    private int front;//对头
    private int rear;//队尾

    //实例队列并设置初始容量
    public CircularQueue(int capacity){
        this.array =new int[capacity];
    }


    /**
     * 入队
     * @param element
     * @throws Exception
     */
    public void offer(int element) throws Exception {
        //队尾不能存值 所以队尾的下一个元素如果是队头 说明队列已满
        if ((rear+1)%array.length==front){
            throw new Exception("队列已满!");
        }
        //将值存入队尾
        array[rear] =element;
        //队尾向后移动
        rear =(rear+1)%array.length;
    }

    /**
     * 出队
     * @return
     * @throws Exception
     */
    public int pull() throws Exception {
        //如果队头等于队尾 则只有一个可能 就是该队为空
        if (rear==front){
            throw new Exception("队列为空!");
        }
        //取出队头元素
        int deQueueElement =array[front];
        //队头向后移动
        front=(front+1)%array.length;
        return deQueueElement;
    }

    /**
     * 输出队列
     * @return
     */
    @Override
    public String toString() {
        StringJoiner sj =new StringJoiner("-");
        for (int i=front;i!=rear;i=(i+1)%array.length){
            sj.add(String.valueOf(array[i]));
        }
        return sj.toString()+"-队尾";
    }
}

测试

/**
 * @author CC
 * @version 1.0
 * @since2023/9/28
 */
public class CTest {
    public static void main(String[] args) throws Exception {
        CircularQueue queue = new CircularQueue(5);
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        queue.offer(4);
        System.out.println("接连将1、2、3、4分别入队后:"+queue);
        queue.pull();
        System.out.println("发生一次出队后:"+queue);
        queue.offer(5);
        System.out.println("将5入队后:"+queue);
    }
}

测试结果


使用队列实现栈

实现原理

通过创建两个队列,一个为出栈队列,一个为入栈队列。首先入栈队列是一直为空的,在入栈时先将元素存入入栈队列,再将出栈队列的元素依次存入入栈队列,这就将刚入元素就被放入了队尾。然后交换两个队列,出栈时将出栈队列队头元素出栈,也就是最早入栈的元素。

/**
 * @author CC
 * @version 1.0
 * @since2023/9/30
 */
public class MyStack {
    private Queue<Integer> queue1; //出栈队列
    private Queue<Integer> queue2; //入栈队列

    /**
     * 初始化栈 底层使用链表存储
     */
    public MyStack() {
        queue1 = new LinkedList<Integer>();
        queue2 = new LinkedList<Integer>();
    }

    /**
     * 入栈
     * @param item
     */
    public void push(int item) {
        //将元素存入队列2
        queue2.offer(item);
        //将队列1中元素依次出队 并存入队列2
        while (!queue1.isEmpty()){
            queue2.offer(queue1.poll());
        }
        //交换队列1 与 队列2
        Queue<Integer> temp = queue1;
        queue1 = queue2;
        queue2 = temp;
    }

    /**
     * 出栈
     * @return
     */
    public int pop(){
        return queue1.poll();
    }

    /**
     * 获取栈顶元素
     * @return
     */
    public int top(){
        return queue1.peek();
    }

    /**
     * 判断该栈是否为空
     * @return
     */
    public boolean isEmpty(){
        return queue1.isEmpty();
    }


    /**
     * 输出栈中元素
     * @return
     */
    @Override
    public String toString() {
        StringJoiner sj =new StringJoiner("-");
        for (Integer integer : queue1) {
            sj.add(String.valueOf(integer));
        }
        return "栈顶"+sj.toString();
    }
}

测试

/**
 * @author CC
 * @version 1.0
 * @since2023/9/30
 */
public class MyStackT {
    public static void main(String[] args) {
        MyStack stack =new MyStack();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        System.out.println("1、2、3、4依次入栈后:"+stack);

        System.out.println("出栈元素:"+stack.pop());
        System.out.println("出栈一次后:"+stack);

        System.out.println("查看栈顶元素(不取出):"+stack.top());

        System.out.println("查看栈顶元素后:"+stack);
        System.out.println("该栈是否为空:"+stack.isEmpty());
        System.out.println("出栈元素:"+stack.pop());
        System.out.println("出栈元素:"+stack.pop());
        System.out.println("出栈元素:"+stack.pop());
        System.out.println("该栈是否为空:"+stack.isEmpty());
    }
}

 测试结果


使用栈实现队列

实现原理

创建两个栈,一个为入队栈、一个为出队栈。入队栈的出栈顺序为后进先出。因为出队时,需要把入队栈的元素依次出栈再入栈到出队栈。后进先出的后进先出就为先进先出。所以出队栈的出栈顺序为先进先出。以此来实现和队列相同逻辑,先进先出。

/**
 * @author CC
 * @version 1.0
 * @since2023/9/30
 */
public class MyQueue {
    private Stack<Integer> inStack =new Stack<>(); //入队栈
    private Stack<Integer> outStack =new Stack<>(); //出队栈

    /**
     * 入队
     * @param item
     */
    public void offer(int item){
        //将出堆栈中的元素依次放入入队栈中
        while (!outStack.isEmpty()){
            inStack.push(outStack.pop());
        }
        //入队栈入栈
        inStack.push(item);
    }

    /**
     * 出队
     * @return
     */
    public int poll(){
        //将入堆栈中的元素依次放入出队栈中
        while (!inStack.isEmpty()){
            outStack.push(inStack.pop());
        }
        //出堆栈出栈
        return outStack.pop();
    }

    /**
     * 判断队中是否为空
     * @return
     */
    public boolean isEmpty(){
        return inStack.isEmpty()&outStack.isEmpty();
    }

    /**
     * 查看队列元素
     * @return
     */
    @Override
    public String toString() {
        while (!inStack.isEmpty()){
            outStack.push(inStack.pop());
        }
        StringJoiner sj =new StringJoiner("-");
        for (Integer integer : outStack) {
            sj.add(integer.toString());
        }
        return "队尾-"+sj.toString();
    }
}

测试

public class MyQueueT {
    public static void main(String[] args) {
        MyQueue myQueue =new MyQueue();
        // 入队
        myQueue.offer(1);
        myQueue.offer(2);
        myQueue.offer(3);
        myQueue.offer(4);
        myQueue.offer(5);
        System.out.println("依次入队1、2、3、4、5后:"+myQueue);

        // 出队
        System.out.println("出队:"+myQueue.poll()); // 1
        System.out.println("出队:"+myQueue.poll()); // 2
        System.out.println("出队:"+myQueue.poll()); // 3
        System.out.println("连续三次出队后:"+myQueue);
        // 入队
        myQueue.offer(6);
        myQueue.offer(7);
        myQueue.offer(8);
        System.out.println("依次入队6、7、8后:"+myQueue);
        // 出队
        System.out.println("出队:"+myQueue.poll()); // 4
        System.out.println("出队:"+myQueue.poll()); // 5
        System.out.println("出队:"+myQueue.poll()); // 6
        System.out.println("连续三次出队后:"+myQueue);
        System.out.println("队内是否为空:"+myQueue.isEmpty());

        System.out.println("出队:"+myQueue.poll()); // 7
        System.out.println("出队:"+myQueue.poll()); // 8
        System.out.println("队内是否为空:"+myQueue.isEmpty());
    }
}

测试结果

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

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

相关文章

树莓派基本配置(2)

安装motion $sudo apt-get update $sudo apt-get install motion配置motion sudo nano /etc/default/motionsudo nano /etc/motion/motion.conf主要改这些参数 //让Motion作为守护进程运行 daemon on ... //用这个端口号来读取数据 stream_port 8081 ... //网络上其它主机…

2023年上海市安全员B证证模拟考试题库及上海市安全员B证理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年上海市安全员B证证模拟考试题库及上海市安全员B证理论考试试题是由安全生产模拟考试一点通提供&#xff0c;上海市安全员B证证模拟考试题库是根据上海市安全员B证最新版教材&#xff0c;上海市安全员B证大纲整理…

正点原子嵌入式linux驱动开发——TF-A使用

上一篇笔记STM32MP157芯片的开发环境&#xff0c;之后就直接简写为MP1。为了保证安全ARM推出了 Arm Trusted Firmware的可信固件&#xff0c;简称 TF-A。它是一个开源的软件&#xff0c;最早是用在Armv8-A&#xff0c;ST也在MP1里面使用到了TF-A。它的作用就是隔离硬件&#xf…

递推+模拟---想好如何存储?

递推模拟 输入输出问题CCF-CSP考试历年真题题型分类分组输入——可能有多组测试数据&#xff0c;对于每组数据 递推---从前面已知态--->后续未知态AcWing 3777. 砖块AcWing 1208. 翻硬币AcWing 1211. 蚂蚁感冒AcWing 3433. 吃糖果AcWing 821. 跳台阶 模拟202212-2-csp-训练计…

C语言--atoi函数详解及模拟实现

本篇概要 本篇博客主要讲述atoi函数的定义&#xff0c;用法及模拟实现。 文章目录 本篇概要1.atoi函数简介2.atoi函数的原型及参数3.atoi函数的使用举例4.atoi函数的模拟实现 1.atoi函数简介 atoi() 是 C语言的一个标准库函数&#xff0c;定义在<stdlib.h>头文件中。 at…

【RocketMQ】基本使用:Java操作RocketMQ(rocketmq-client)

【RocketMQ】基本使用&#xff1a;Java操作RocketMQ&#xff08;rocketmq-client&#xff09; 1.引入依赖 <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-client</artifactId><version>4.3.2</version>…

公司知识库搭建步骤,知识库建设与运营的四个步骤分享

在知识管理方面&#xff0c;团队中的每一员&#xff0c;都像是一名独行侠&#xff0c;自己的知识&#xff0c;满足自己的需要&#xff0c;这其中&#xff0c;就造成了很多无意义的精力消耗。 公司知识库搭建必要性 比如&#xff0c;一名员工撰写一QA文档&#xff0c;并没有将它…

CDH 6.3.2升级Flink到1.17.1版本

CDH&#xff1a;6.3.2 原来的Flink&#xff1a;1.12 要升级的Flink&#xff1a;1.17.1 操作系统&#xff1a;CentOS Linux 7 一、Flink1.17编译 build.sh文件&#xff1a; #!/bin/bash set -x set -e set -vFLINK_URLsed /^FLINK_URL/!d;s/.*// flink-parcel.properties FLI…

【模板语法+数据绑定+el与data的两种写法+MVVM模型】

模板语法数据绑定el与data的两种写法MVVM模型 1 模板语法1.1 插值语法1.2 指令语法 2 数据绑定2.1 单向数据绑定2.2 双向数据绑定 3 el与data的两种写法4 MVVM模型 1 模板语法 1.1 插值语法 双大括号表达式功能&#xff1a;用于解析标签体内容语法&#xff1a;{{xxx}}&#x…

Postman的高级用法—Runner的使用

1.首先在postman新建要批量运行的接口文件夹&#xff0c;新建一个接口&#xff0c;并设置好全局变量。 2.然后在Test里面设置好要断言的方法 如&#xff1a; tests["Status code is 200"] responseCode.code 200; tests["Response time is less than 10000…

分子相互作用的人工智能

8 分子相互作用的人工智能 正如在第 5、6 和 7 节中所描述的那样&#xff0c;人工智能已经彻底改变了分子学习、蛋白质科学和材料科学领域。尽管已经广泛研究了用于单个分子的人工智能&#xff0c;但分子的物理和生物功能通常是由它们与其他分子的相互作用驱动的。在本节中&am…

iPhone数据丢失怎么办?9 佳免费 iPhone 数据恢复软件可收藏

您是否知道有多种原因可能导致 iPhone 上存储的数据永久丢失&#xff1f;然而&#xff0c;使用一些最好的免费 iPhone 数据恢复软件&#xff0c;您仍然可以恢复它。 由于我们几乎总是保存手机上的所有内容&#xff08;从联系人到媒体文件&#xff09;&#xff0c;因此 iPhone …

MySQL学习笔记27

MySQL主从复制的核心思路&#xff1a; 1、slave必须安装相同版本的mysql数据库软件。 2、master端必须开启二进制日志&#xff0c;slave端必须开启relay log 日志。 3、master主服务器和slave从服务器的server-id号不能一致。 4、slave端配置向master端来同步数据。 master…

【Java 进阶篇】MySQL 数据控制语言(DCL):管理用户权限

MySQL 是一个强大的关系型数据库管理系统&#xff0c;提供了丰富的功能和选项来管理数据库和用户。数据库管理员&#xff08;DBA&#xff09;通常使用数据控制语言&#xff08;Data Control Language&#xff0c;简称 DCL&#xff09;来管理用户的权限和访问。 本文将详细介绍…

基于php+MySql实现简易留言板(超级详细!)

基于phpMySql实现简易留言板&#xff08;超级详细&#xff01;&#xff09; 这篇文章是基于PHP和MySQL实现的一个简易留言板。该留言板具有用户注册、登录、发表留言以及查看留言等功能。首先&#xff0c;用户可以通过注册功能创建自己的账号&#xff0c;然后使用该账号进行登…

WPF 实现点击按钮跳转页面功能

方法1. 配置环境 首先添加prism依赖项&#xff0c;配置好所有文件。需要配置的有两个文件&#xff1a;App.xaml.cs和App.xaml App.xaml.cs using System.Data; using System.Linq; using System.Threading.Tasks; using System.Windows;namespace PrismDemo {/// <summa…

Linux 集锦 之 最常用的几个命令

Linux最常用的几个命令 ​ Linux系统中的命令那是相当地丰富&#xff0c;不同的版本可能还有不同的命令&#xff0c;不过Linux核心自带的命令大概有几百个&#xff0c;这个不管是什么发行版一般都是共用的。 ​ 如果希望探索Linux的所有命令&#xff0c;可能不太实际&#xf…

【Unity Build-In管线的SurfaceShader剖析_PBS光照函数】

Unity Build-In管线的SurfaceShader剖析 在Unity Build-In 管线&#xff08;Universal Render Pipeline&#xff09;新建一个Standard Surface Shader文件里的代码如下&#xff1a;选中"MyPBR.Shader"&#xff0c;在Inspector面板&#xff0c;打开"Show generat…

力扣刷题-哈希表-求两个数组的交集

349 求两个数组的交集 题意&#xff1a;给定两个数组&#xff0c;编写一个函数来计算它们的交集。注意&#xff1a;输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 提示&#xff1a; 1 < nums1.length, nums2.length < 1000 0 < nums1[i], …

TensorFlow-Federated简介与安装

1、简介 TensorFlow Federated&#xff08;TFF&#xff09;是一个用于机器学习和其他分布式数据计算的开源框架。TFF 的开发旨在促进联邦学习 &#xff08;FL&#xff09;的开放研究和实验。联邦学习是一种机器学习方法&#xff0c;其中一个共享的全局模型在许多参与的客户之间…