【leetcode】栈与队列

news/2025/1/16 7:50:57/

1. 有效的括号

OJ:有效的括号

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

有效字符串需满足:

(1)左括号必须用相同类型的右括号闭合。

(2)左括号必须以正确的顺序闭合。

(3)每个右括号都有一个对应的相同类型的左括号。

示例 1:

输入:s = "()"

输出:true

示例 2:

输入:s = "()[]{}"

输出:true

示例 3:

输入:s = "(]"

输出:false

解题思路

(1)左括号,直接入栈

(2)右括号,与栈顶的左括号进行匹配,如果不匹配直接返回false;否则继续循环

 循环结束后,如果栈空则匹配,否则左括号比右括号多肯定不匹配

public boolean isValid(String s) {Stack<Character> stack = new Stack<>();for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);if (c == '[' || c == '{' || c == '('){stack.push(c);}else {if (stack.isEmpty()){return false;}char temp = stack.peek();if (c == '}' && temp == '{'){stack.pop();continue;}if (c == ']' && temp == '['){stack.pop();continue;}if (c == ')' && temp == '('){stack.pop();continue;}return false;}}return stack.isEmpty();}

2. 逆波兰表达式求值

OJ:

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 (也叫后缀表达式:将运算符写在操作数之后)表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

示例 1:

输入:tokens = ["2","1","+","3","*"]

输出:9

解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

输入:tokens = ["4","13","5","/","+"]

输出:6

解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

示例 3:

输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]

输出:22

解释:该算式转化为常见的中缀算术表达式为:

   ((10 * (6 / ((9 + 3) * -11))) + 17) + 5

= ((10 * (6 / (12 * -11))) + 17) + 5

= ((10 * (6 / -132)) + 17) + 5

= ((10 * 0) + 17) + 5

= (0 + 17) + 5

= 17 + 5

= 22

解题思路

对tokens数组进行遍历,依次获取到每个元素,如果:

(1)该元素是数字(注意:不是运算符肯定是数字),将该数字入栈

(2)该元素是运算符,从栈顶获取该运算符对应的右左操作数,进行相应的操作,最后将结果入栈

(3)循环结束后,栈顶的元素就是最终表达式的结果

public int evalRPN(String[] tokens) {Stack<Integer> s = new Stack<>();for(String e : tokens){// 如果是数字,直接入栈if(!(e.equals("+") || e.equals("-") || e.equals("*") || e.equals("/"))){s.push(Integer.valueOf(e));}else{// 说明e是个操作符// 从栈顶取两个数字作为该操作符的右左操作数,// 注意:栈是后进先出,所以先取到的是右操作数,后取到的是左操作数int right = s.pop();int left = s.pop();// 进行对应的操作,然后将结果入栈switch(e){case "+":s.push(left + right);break;case "-":s.push(left - right);break;case "*":s.push(left * right);break;case "/":s.push(left / right);break;}}}// 最终栈顶元素就是最后的结果return s.peek();}}

3. 最小栈

OJ:最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

        MinStack() 初始化堆栈对象。

        void push(int val) 将元素val推入堆栈。

        void pop() 删除堆栈顶部的元素。

        int top() 获取堆栈顶部的元素。

        int getMin() 获取堆栈中的最小元素。

示例 1:

输入: ["MinStack","push","push","push","getMin","pop","top","getMin"]

                [[],[-2],[0],[-3],[],[],[],[]]

输出: [null,null,null,null,-3,null,0,-2]

解释: MinStack minStack = new MinStack();

            minStack.push(-2);

            minStack.push(0);

            minStack.push(-3);

            minStack.getMin(); --> 返回 -3.

            minStack.pop(); minStack.top(); --> 返回 0.

            minStack.getMin(); --> 返回 -2.

解题思路

  • 思路1

(1)利用两个栈,一个为正常栈(保存所有的进出栈数据),一个为最小栈(只有当数据为最小时,才会入栈)

(2)核心在于:入栈时,若数据最小,需要两个栈都要入栈,出栈时,如果出的数据为最小,需要更新最小栈

Stack<Integer> dataSt;  // 存放数据Stack<Integer> minSt;   // 存放最小值public MinStack() {dataSt = new Stack<>();minSt = new Stack<>();}// 入栈时:// 数据栈:每次都要压入一个元素// 最小值栈:当最小值栈为空 或者 当前插入元素小于最小值栈栈顶元素时入栈public void push(int val) {dataSt.push(val);if(minSt.isEmpty() || val <= minSt.peek()){minSt.push(val);}}// 出栈时:// 最小值栈:栈顶与数据栈栈顶元素相等时才可以出,注意使用equals比较// 数值栈每次都要出一个元素public void pop() {if(dataSt.peek().equals(minSt.peek())){minSt.pop();}dataSt.pop();}public int top() {return dataSt.peek();}public int getMin() {return minSt.peek();}
  • 思路2

利用两个栈,一个正常栈s1,一个存最小栈s2,两个栈为空时,直接入栈;栈不为空时,s1正常入栈,判断入栈元素与栈s2的栈顶元素的大小,比栈顶元素小,元素入s2栈;比栈顶元素大,将栈顶元素再次入栈。
出栈时两个栈顶元素一起出栈,检查栈顶元素时,检查栈s1的,检查最小元素时,检查s2的栈顶元素。

//    保存数值Stack<Integer> s1 = new Stack<>();
//    保存最小数Stack<Integer> s2 = new Stack<>();public MinStack() {s1 = new Stack<>();s2 = new Stack<>();}public void push(int val) {s1.push(val);if (s2.isEmpty()){s2.push(val);}else {int temp = s2.peek();if (val < temp){s2.push(val);}else {s2.push(temp);}}}public void pop() {s1.pop();s2.pop();}public int top() {return s1.peek();}public int getMin() {return s2.peek();}

4. 验证栈序列

OJ:验证栈序列

给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;否则,返回 false 。

示例 1:

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]

输出:true

解释:我们可以按以下顺序执行: push(1), push(2), push(3), push(4), pop() -> 4, push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1

示例 2:

输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]

输出:false

解释:1 不能在 2 之前弹出。

解题思路

入栈:当栈为空,或者栈顶元素和待出栈元素不相等时

注意:入栈时要保证有元素,如果没有元素则一定不相等

出栈:当栈顶元素待出栈元素相同时出栈

循环进行上述过程即可,直到所有的元素全部出栈

将pushed数组的元素入栈,判断栈顶元素与popped[i]是否相等,相等出栈再将i++,直到栈顶元素与popped[i]不相等,进去下一次循环。最后栈为空时,栈序列正确,不为空栈序列错误。

public boolean validateStackSequences(int[] pushed, int[] popped) {int i = 0;Stack<Integer> stack = new Stack<>();for (int val:pushed) {stack.push(val);while (!stack.isEmpty()&&stack.peek() == popped[i]){stack.pop();i++;}}return stack.isEmpty();}

5. 用队列实现栈

OJ:用队列实现栈

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。

实现 MyStack 类:

        void push(int x) 将元素 x 压入栈顶。

        int pop() 移除并返回栈顶元素。

        int top() 返回栈顶元素。

        boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

解题思路

  • 思路1

借助两个队列来模拟实现栈。一个队列是辅助的,起到导元素的作用。

入栈:先将元素放入a队列中,如果b不空,将b中所有元素导入到a中。此时,刚刚入栈的元素刚好在a的队头,然后将a和b队列交换下。即:b队列队头相当于栈顶,b队列队尾相当于栈底

出栈:  直接从b中poll()即可

获取栈顶元素:直接从b中peek()即可

    private Queue<Integer> a;  // a是用来辅助导元素的private Queue<Integer> b;  // 元素全部放在b中public MyStack() {a = new LinkedList<>();b = new LinkedList<>();}public void push(int x) {// 先把元素放入a队列中a.offer(x);while(!b.isEmpty()){a.offer(b.poll());}Queue<Integer> temp = a;a = b;b = temp;}public int pop() {return b.poll();}public int top() {return b.peek();}public boolean empty() {return b.isEmpty();}
  • 思路2

先将元素放入队列中,再将元素前面的所有元素依次入队

    Queue<Integer> queue = new LinkedList<>();public MyStack() {}public void push(int x) {if (queue.isEmpty()){queue.offer(x);return;}int size = queue.size();queue.offer(x);while (size != 0){queue.offer(queue.poll());size--;}}public int pop() {return queue.poll();}public int top() {return queue.peek();}public boolean empty() {return queue.isEmpty();}

6. 用栈实现队列

OJ:用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

        void push(int x) 将元素 x 推到队列的末尾

        int pop() 从队列的开头移除并返回元素

        int peek() 返回队列开头的元素

        boolean empty() 如果队列为空,返回 true ;否则,返回 false

解题思路

利用两个栈模拟实现队列

s2作为辅助栈,s1作为真正存储的栈。

    Stack<Integer> s1 = new Stack<>();Stack<Integer> s2 = new Stack<>();public MyQueue() {}public void push(int x) {while (!s1.isEmpty()){s2.push(s1.pop());}s1.push(x);while (!s2.isEmpty()){s1.push(s2.pop());}}public int pop() {return s1.pop();}public int peek() {return s1.peek();}public boolean empty() {return s1.isEmpty();}

7. 设计循环队列

 OJ:设计循环队列

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

        MyCircularQueue(k): 构造器,设置队列长度为 k 。

        Front: 从队首获取元素。如果队列为空,返回 -1 。

        Rear: 获取队尾元素。如果队列为空,返回 -1 。

        enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。

        deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。

        isEmpty(): 检查循环队列是否为空。

        isFull(): 检查循环队列是否已满。

解题思路

参考这一篇:循环队列

    private int head;private int tail;private int size;int data[];public MyCircularQueue(int k) {data = new int[k + 1];head = tail = 0;}public boolean enQueue(int value) {if(isFull()){return false;}data[tail] = value;tail = (tail + 1) % data.length;size ++;return true;}public boolean deQueue() {if(isEmpty()){return false;}head = (head + 1) % data.length;size --;return true;}public int Front() {if(isEmpty()){return -1;}return data[head];}public int Rear() {if(isEmpty()){return -1;}return data[(tail - 1 + data.length) % data.length];}public boolean isEmpty() {return size == 0;}public boolean isFull() {return size == data.length - 1;}


http://www.ppmy.cn/news/35725.html

相关文章

Xilinx FPGA Multiboot设计与实现(Spartan-6和Kintex-7为例)

文章目录 1. FPGA固件升级方案2. Golden镜像和Multiboot镜像简介3. ISE环境下实现(XC6SLX9)4. Vivado环境下实现(XC7K325T)5. Golden镜像Header分析6. 参考资料7. 示例工程ISE、Vivado、MicroBlaze系列教程 1. FPGA固件升级方案 FPGA的硬件可编程性给设计带来了很高的灵活…

每日学术速递3.29

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.CC3D: Layout-Conditioned Generation of Compositional 3D Scenes 标题&#xff1a;CC3D&#xff1a;合成 3D 场景的布局条件生成 作者&#xff1a;Sherwin Bahmani, Jeong Joon …

设计模式-建造者模式

建造者模式是一种创建型设计模式&#xff0c;它允许你创建复杂对象的不同表示&#xff0c;而无需直接与其构造函数参数进行交互。建造者模式将一个复杂对象的构建与其表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 建造者模式的核心思想是将一个复杂对象的构建…

使用StaMPS_Visualizer

0 前言 StaMPS-Visualizer &#xff1a;由thho开发的用于可视化由StaMPS / MTI处理的DInSAR结果。 github地址&#xff1a;StaMPS-Visualizer 使用StaMPS_Visualizer需要配置好StaMPS&#xff0c;并安装好R和Rstudio Ubuntu中安装StaMPS StaMPS-Visualizer 安装步骤–在linux…

算法:贪婪算法、分而治之

算法&#xff1a;贪婪算法、分而治之 文章目录1.贪婪算法计数硬币实例12.分而治之分割/歇征服/解决合并/合并实例23.动态规划对照实例34.基本概念算法数据定义数据对象内置数据类型派生数据类型基本操作1.贪婪算法 设计算法以实现给定问题的最佳解决方案。在贪婪算法方法中&am…

nodejs+vue手机数码电子网上购物商城电商推荐系统elementui

管理员登陆后&#xff0c;主要功能模块包括首页、个人中心、用户管理、商品分类管理、商品信息管理、系统管理、订单管理等功能。 用户进入系统可以进行首页、商品信息、公告信息、个人中心、后台管理、购物车、在线客服息管理等操 开发语言&#xff1a;nodejsvueelementui 框架…

【虚幻引擎UE】UE5核心效率插件推荐

一、UnrealEditorPythonScripts (基于UE5 的Python支持插件) 支持Python语言基于UE5进行开发 GIT地址:https://github.com/mamoniem/UnrealEditorPythonScripts 二、Haxe-UnrealEngine5 (基于UE5 的Haxe支持插件) Haxe是一门新兴的开源编程语言,是一种开源的编程语言。…

ElasticSearch - SpringBoot整合ES:精确值查询 term

文章目录00. 数据准备01. ElasticSearch 结构化搜索是什么&#xff1f;02. ElasticSearch 结构化搜索方式有哪些&#xff1f;03. ElasticSearch 全文搜索方式有哪些&#xff1f;04. ElasticSearch term 查询数字&#xff1f;05. ElasticSearch term 查询会不会计算评分&#xf…