[算法] 栈和队列

article/2025/9/15 13:24:24

        欢迎来到老胡的算法解题思路,本文章主要使用的语言为java,使用的题型为力扣算法题,基于这一篇文章,我将为你介绍栈和队列的基础知识和栈和队列的题型,喜欢的朋友可以关注一下,下次更新不迷路!

目录

前言

一、栈和队列的常用方法

二、栈和队列题型

2.1、栈和队列的相互实现

2.2、括号类题型

2.3、找元素问题

2.4、数组去重

2.5、最大面积

三、总结


前言

        栈和队列是一组有序列表,是功能受限的线性表结构,可以用数组或链表来实现,队列数据存取先入先出,栈先入后出。队列是基于地址指针进行遍历,从头部或尾部进行遍历,不需要开辟空间,因为在遍历的过程中数据结构不受影响。栈只能从顶部取数据,也就是说最先进入栈底的,需要遍历整个栈才能取出来,需要遍历数据时需要开辟临时空间,保持数据在遍历前的一致性。


一、栈和队列的常用方法

    //栈Stackpush()//入栈empty()//栈空返回真,否则为假peek()//获取栈顶值,不出栈pop()//获取栈顶值,出栈get()//获得栈中对应值//队列Queue和优先队列PriorityQueueadd()//入队offer()//将指定元素插入队列,成功返回true,否则返回falsepeek()//获取队头的值,但不出队poll()//获取并移除队头remove()//获取并移除队头//双向队列DequeaddFirst()//从队列头部插入数据addLast()//从队列尾部插入数据removeFirst()//从队列头部删除数据removeLast()//从队列尾部删除数据pollFirst()//获取并移除队头pollLast()//获取并移除队尾peekFirst()//获取队头的值,但不出队peekLast()//获取队头的值,但不出队

二、栈和队列题型

2.1、栈和队列的相互实现

例题:力扣225.用队列实现栈

 分析:题目分析

针对这道题,队列实现栈,注意栈的定义,先进后出,再想想队列的种类,这个题直接使用双向队列就可以解题。反过来,如果遇到栈实现队列,可以选用两个栈来处理,一个存储数据,一个进行数据间的转换。这里,为啥选取这个题,一来是为了让初学者更好的理解栈和队列,同时也为了让初学者理解双向队列,在以后遇到栈的问题,可以用双向队列来实现。

解题:完整代码

class MyStack {// 声明双向队列Deque<Integer> deque;public MyStack() {deque = new LinkedList<Integer>();}// 将元素压入栈顶public void push(int x) {deque.addFirst(x);}// 移除并返回栈顶元素public int pop() {return deque.removeFirst();}// 返回栈顶元素public int top() {return deque.peekFirst();}// 判断是否为空public boolean empty() {return deque.isEmpty();}
}

2.2、括号类题型

例题:力扣921.使括号有效的最少添加

 分析:题目分析

        针对这类题型,可以使用栈来解题,采取遇到左括号就⼊栈,遇到右括号就去栈中寻找最近的左括号,看是否匹配的策略

分析:解题模板

    boolean isValid(String str) {
//        声明字符类型的栈Stack<Character> stack = new Stack<>();
//        字符串转数组直接遍历,也可用其他便利方法char[] str1 = str.toCharArray();for (char ch : str1) {
//            左括号入栈,右括号出栈if (ch == '(' || ch == '{' || ch == '[')stack.push(ch);else {if (!stack.empty() && transform(ch) == stack.peek())stack.pop();elsereturn false;}}
//        栈为空,匹配成功,反之则不成功return stack.empty();
//        字符转换函数}char transform(char ch) {if (ch == '}') return '{';if (ch == ')') return '(';return '[';}

解题:完整代码

class Solution {public int minAddToMakeValid(String S) {int ans=0;// 构建栈Stack<Character> stack=new Stack<>();for(int i=0;i<S.length();i++){// 匹配字符if(S.charAt(i)=='('){// 入栈stack.push('(');}else if(stack.isEmpty()){ans++;}else{stack.pop();}}return ans+stack.size();}
}

2.3、找元素问题

例题:力扣556.下一个更大元素|||

 分析:题目分析

        对于这一类题型,可以直接暴力解,但是暴力的话时间复杂度太高,可以考虑采用优先队列的方式,让他们的值排序,然后就选取出稍微比当前位大一点的数,后面的直接用排列的最小数就可以还原。当然了,还要注意判断数据是否溢出。

解题:完整代码

class Solution {public int nextGreaterElement(int n) {//优先队列PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();// 计数,*10后用于n数据的还原int count1 = 1;//判断开关,防止多次条件成功int count2 = 0;//存储低一位的数int count=Integer.MIN_VALUE;while(n!=0){int num = n%10;//对应后面的数据还原n = n/10;// 进入队列priorityQueue.add(num);//判断后一位数和前一位,看是否满足关系if(count>num){n=n*10;while(!priorityQueue.isEmpty()){// 出队列int num1 = priorityQueue.poll();if(count2==0&&num<num1){count2 = 1;//判断是否溢出if(n>Integer.MAX_VALUE/10 || (n==Integer.MAX_VALUE/10&&num1>7)){return -1;}// 数值还原n = n+num1*count1;}else{// 判断是否溢出if(n>Integer.MAX_VALUE/10 || (n==Integer.MAX_VALUE/10&&num1>7)){return -1;}count1*=10;// 数值还原n = n*10+num1;}}return n;}// 后一位数更新count = num;}return -1;}
}

2.4、数组去重

例题:力扣316.去除重复字母

 分析:题目分析

        关于去重算法,给我们的第一反应,直接用哈希表解决就可以了,但是看到这类比较复杂的去重,有不知道从何下手。如果我们想要有序的结果,那就得对原字符串排序,排序后再去重,但是排序后就不得不打乱其他字符的位置了,这显然解法是错误的,针对这种题型,我们可以考虑用单调栈来解,先用一个数组标记每个元素重复的此时,在通过元素和栈顶元素的比较以及元素出现的次数是否满足条件来阶梯。

解题:完整代码

class Solution {public String removeDuplicateLetters(String s) {int[] ans = new int[26];for (int i = 0; i < s.length(); i++) {
//            给ans数组赋值,记录每个元素出现的次数ans[s.charAt(i) - 'a']++;}
//        单调栈初始化Stack<Character> stack = new Stack<>();for (int i = 0; i < s.length(); i++) {char ch = s.charAt(i);
//            如果栈中已经存在该元素,数组对应出现次数减一if (stack.contains(ch)){ans[ch - 'a']--;continue;}
//            如果栈非空并且栈顶元素字典值大并且栈顶值出现不止一次while (!stack.isEmpty() && stack.peek() > ch && ans[stack.peek() - 'a'] > 1){
//                移除该元素并且对应的出现次数减一char ch1 = stack.pop();ans[ch1 - 'a']--;}
//            入栈stack.push(ch);}
//        合成字符串答案String answer = "";for (int i = 0; i < stack.size(); i++) {answer+=stack.get(i);}return answer;}
}

2.5、最大面积

例题:力扣84.柱状图中最大的矩形

分析:题目分析

        对于这一类题型,可以直接暴力解,但是暴力的话时间复杂度太高,同时容易出错,也可以使用动态规划来解,方法不唯一,但在这,我介绍的是用单调栈来解。解题时先通过单调栈寻找到比上一个元素小的值,求出这个值对应的最大面积 ,同时通过进栈和出栈使得栈里面元素单调,在通过这个栈求解对应的最大面积,两者相比即可。

解题:完整代码

class Solution {public int largestRectangleArea(int[] heights) {int len = heights.length;
//        初始化高度和宽度int height = 0;int width = 0;int area=0;int num = 0;
//        初始化单调栈Stack<Integer> stack = new Stack<>();for(int i=0;i<len;i++) {
//            右边高度小于左边高度且栈不为空时,通过while解出当前位置能得到的最大面积while (!stack.isEmpty() && heights[i] < heights[stack.peek()]) {
//             移除栈顶元素,并根据这个值找到对应高度num = stack.pop();height=heights[num];
//                根据栈得出对应宽度if(!stack.isEmpty()){width=i-stack.peek()-1;}else{width = i;}
//                得出最大面积area=Math.max(area,height*width);}
//            如果栈为空或者下一个高度大于上一个高度,入栈stack.push(i);}
//        正面扫描完毕,逆向继续扫描while (!stack.isEmpty()) {
//             移除栈顶元素,并根据这个值找到对应高度num = stack.pop();height=heights[num];
//                根据栈得出对应宽度if(!stack.isEmpty()){width=len-1-stack.peek();}else{width=len;}
//            求出最大面积area = Math.max(area,height*width);}return area;}
}

三、总结

        栈和队列是功能受限的线性表结构,在实际的算法解题中,不推荐使用栈,因为栈继承了Vector,同时栈中是用了大量的synchronized修饰,虽然线程安全,但是效率大打折扣,推荐使用队列中的双向队列Deque来实现栈的基本操作。

        补充说明:栈和队列还存在很多没有总结到的典型题型,后期总结后继续补上


http://chatgpt.dhexx.cn/article/oN0J6PZc.shtml

相关文章

十道经典面试算法真题详解

前言 分享一下 腾讯常考的十道算法题&#xff08;真题&#xff09;。在金三银四&#xff0c;希望对大家有帮助呀。 重排链表 最长递增子序列 环形链表 反转链表 最长回文子串 全排列 LRU 缓存 合并K个升序链表 无重复字符的最长子串 删除链表的倒数第 N 个结点 1. …

队列相关习题

1.已知循环队列存储在一维数组A0…n-1]中&#xff0c;且队列非空时front和rear分别指向队头元素和队尾元素。若初始时队列为空&#xff0c;且要求第一个进入队列的元素存储在A[0]处&#xff0c;则初始时front和rear的值分别是( )。 A.0&#xff0c;0 B. 0&#xff0c;n-1 C. n-…

java算法面试题_Java算法面试题汇总

原标题&#xff1a;Java算法面试题汇总 1. 字符串 如果IDE没有代码自动补全功能&#xff0c;所以你应该记住下面的这些方法。 toCharArray() // 获得字符串对应的char数组 Arrays.sort() // 数组排序 Arrays.toString(char[] a) // 数组转成字符串 charAt(int x) // 获得某个索…

详解单调队列算法

前言 嘿!彩蛋!感觉有帮助就三连呗! 如果你对这篇文章可感兴趣,可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」,查看完整博客分类与对应链接。 在上一篇文章中,我们介绍了「单调栈」这一最常考察的线性数据结构。而今天我们将继续沿着这个思路,介绍另…

栈和队列相关经典算法题总结(数据结构+C语言)

我们这里针对栈和队列的一些经典算法题做详细讲解: 1.括号匹配问题. 2.用队列实现栈. 3.用栈实现队列. 4.设计循环队列. 一.详细讲解如下: 1.括号匹配问题.(如下图) 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &am…

qt使用消息队列服务器,qt代码实现消息队列通信

qt代码实现消息队列通信 内容精选 换一换 HBase 1.X版本在RPC流程中&#xff0c;多个数据通信线程会争抢同一个缓存Buffer队列&#xff0c;代码以lock重入锁实现线程安全&#xff0c;锁抢占严重&#xff0c;导致HBase不能充分发挥CPU多核的能力。HBase 1.X版本的RPC通信机制中B…

消息队列MQ常见面试题

面试官在面试候选人时&#xff0c;如果发现候选人的简历中写了在项目中使用了 MQ 技术&#xff08;如 Kafka、RabbitMQ、RocketMQ&#xff09;&#xff0c;基本都会抛出一个问题&#xff1a;在使用 MQ 的时候&#xff0c;怎么确保消息 100% 不丢失&#xff1f; 这个问题在实际…

RabbitMQ消息队列常见面试题总结

1、什么是消息队列&#xff1a; 1.1、消息队列的优点&#xff1a; &#xff08;1&#xff09;解耦&#xff1a;将系统按照不同的业务功能拆分出来&#xff0c;消息生产者只管把消息发布到 MQ 中而不用管谁来取&#xff0c;消息消费者只管从 MQ 中取消息而不管是谁发布的。消息…

【消息队列】面试题及答案整理

消息队列面试题 为什么要使用消息队列/消息队列的应用场景使用了消息队列会有什么缺点如何保证消息队列是高可用的RocketMQ是如何保证消息队列是高可用的 如何保证消息不被重复消费/如何保证消息消费的幂等性如何保证消费的可靠性传输RocketMQ如何保证消费的可靠性传输RabbitMQ…

JAVA——快速排序(详细)

JAVA快速排序的实现 快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高&#xff0c;因此经常被采用&#xff0c;再加上快速排序思想----分治法也确实实用&#xff0c;因此很多软件公司的笔试面试&#xff0c;包括像腾讯&#xff0c;微软等知名IT公司都喜欢考这个&…

快速排序算法(java实现)

基本思想 快速排序是一种采用分治法解决问题的一个典型应用&#xff0c;也是冒泡排序的一种改进。它的基本思想是&#xff0c;通过一轮排序将待排记录分割成独立的两部分&#xff0c;其中一部分均比另一部分小&#xff0c;则可分别对这两部分继续进行排序&#xff0c;已达到整…

java快速排序(含快速排序代码)

目录 一&#xff1a;快速排序思想 二&#xff1a;快速排序代码&#xff08;pivot一定时先和arrays【r】先比较&#xff09; 三&#xff1a;结果 一&#xff1a;快速排序思想 假设我们现在对“6 1 2 7 9 3 4 5 10 8”这个10个数进行排序。首先在这个序列中随便找一个数作为基准…

快速排序 Java 实现

概念 快速排序&#xff08;Quicksort&#xff09;是对冒泡排序的一种改进。 参考: [数据结构与算法(Kotlin语言)]1.冒泡排序&#xff08;Bubble Sort&#xff09; 快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略&#xff0c;通常称其为分治法(…

java快速排序详解

文章目录 一、快排原理二、实例操作三、实战代码四、总结 一、快排原理 从待排序区间选择一个数&#xff0c;作为基准值&#xff08;pivot&#xff09;&#xff1b;遍历整个待排序区间&#xff0c;将比基准值小的&#xff08;可等于&#xff09;放到基准值左边&#xff0c;将比…

快速排序Java

基本思想 快速排序的基本思想&#xff1a;通过一趟排序将待排记录分隔成独立的两部分&#xff0c;其中一部分记录的关键字均比另一部分的关键字小&#xff0c;则可分别对这两部分记录继续进行排序&#xff0c;以达到整个序列有序。 算法描述 快速排序使用分治法来把一个串&…

快速排序 Java模板

快速排序Java模板 详情参考 https://www.acwing.com/problem/content/787/ https://www.acwing.com/solution/content/2096/ 快速排序的整体过程&#xff0c;动态变化流程 以从小到大排序为例 选择一个目标参考值 p i v i t pivit pivit&#xff0c;通常课本上会说选择数组…

java 实现快速排序

1.介绍 快速排序是对冒泡排序的一种改进。它的基本思想是&#xff1a;通过一趟排序将要排序的数据分割成独立的两部分&#xff0c;其中一 部分的所有数据都比另外一部分的所有数据都要小&#xff0c;然后再按此方法对这两部分数据分别进行快速排序&#xff0c;整个排序 过程可以…

使用 Java 实现快速排序(详解)

一、概述 最近在看一些面试题&#xff0c;发现很多面试过程中都会要求手写快速排序&#xff0c;查阅一些博客发现别人写的并不是特别清楚而且也很难记住&#xff0c;所以为了更好的掌握这个算法&#xff0c;所以在这篇文章中&#xff0c;将自己的学习过程记录下来&#xff0c;…

【JAVA】快速排序

快排&#xff0c;和冒泡排序一样&#xff0c;是同一类型的排序&#xff0c;都是交换排序 交换&#xff0c;涉及在遍历中比较&#xff0c;然后相互交换元素 冒泡排序是根据趟数两两比较&#xff0c;边比较边交换&#xff0c;快排也一样&#xff0c;不过冒泡是以顺序表的格式进…

快速排序Java代码实现

代码实现&#xff08;附注释&#xff09; import java.util.Arrays;public class Main {public static void main(String[] args) {int[] arr {9, 3, 7, 3, 6, 5, 3, 2, 1, 0};System.out.println("排序前&#xff1a;");System.out.println(Arrays.toString(arr))…