栈的经典算法问题(算法村第四关白银挑战)

括号匹配问题

有效的括号

20. 有效的括号 - 力扣(LeetCode)

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

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

输入:s = "()"
输出:true

示例 2:

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

示例 3:

输入:s = "(]"
输出:false

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成
利用HashMap
public boolean isValid(String s){HashMap<Character, Character> hashMap = new HashMap<>();//key为左括号,value为右括号hashMap.put('(',')');hashMap.put('[',']');hashMap.put('{','}');ArrayDeque<Character> stack = new ArrayDeque<>();for (int i = 0; i < s.length(); i++){char c = s.charAt(i);if(hashMap.containsKey(c))  //c是左括号stack.push(c);  //左括号入栈else    //c是右括号{//栈空,或者该右括号与栈顶的左括号不匹配if (stack.isEmpty() || c != hashMap.get(stack.peek()))return false;else //匹配stack.pop();    //栈顶的左括号出栈}}//循环结束后,若栈空则s是括号有效的字符串,否则说明还有左括号没匹配return stack.isEmpty();}
非HashMap版
public boolean isLeftBracket(char c){return c == '(' || c == '{' || c == '[';}public char partner(char c){switch(c){case ')': return '(';case '}': return '{';case ']': return '[';default: return ' ';}}public boolean isValid(String s) {//括号总数必须是偶数if(s.length() % 2 != 0)return false;Stack<Character> stack = new Stack<>();for(int i = 0; i < s.length(); i++){char c = s.charAt(i);if(isLeftBracket(c))    //c是左括号stack.push(c);else    //c是右括号{   //栈空,或者该右括号与栈顶的左括号不匹配if(stack.isEmpty() || stack.peek() != partner(c))return false;else    //匹配stack.pop();  //栈顶的左括号出栈}}return stack.isEmpty(); //栈空则s是括号有效的字符串,栈不空说明还有左括号没匹配}

括号生成

22. 括号生成 - 力扣(LeetCode)

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

示例 2:

输入:n = 1
输出:["()"]

提示:

  • 1 <= n <= 8
深搜,做减法

在这里插入图片描述

public List<String> generateParenthesis(int n)
{//特判if (n == 0)return null;//结果集ArrayList<String> res = new ArrayList<String>();//深搜,找出全部有效括号组合DFS(res, n, n, "");return res;
}/*** @param res 结果集* @param left 左括号还能用几个* @param right 右括号还能用几个* @param curStr 当前递归所得到的字符串*/
public static void DFS(List<String> res, int left, int right, String curStr)
{//递归终止;将一种组合添加到结果集if (left == 0 && right == 0){res.add(curStr);return;}//尝试使用右括号后,若左括号剩余数量大于右括号剩余数量,则“剪枝”(否则会违背有效括号的定义)if (left > right)return;//优先使用左括号if (left > 0)DFS(res, left - 1, right, curStr + "(" );//使用右括号if (right > 0)DFS(res, left, right - 1, curStr +")" );
}
深搜,做加法

在这里插入图片描述

public List<String> generateParenthesis(int n)
{//特判if (n == 0)return null;//结果集ArrayList<String> res = new ArrayList<String>();//深搜,寻找全部有效括号组合DFS(res, 0, 0, "", n);return res;
}/*** @param res 结果集* @param left 左括号使用了几个* @param right 右括号使用使用了几个* @param curStr 当前递归所得到的字符串* @param n 题目所给的括号生成对数*/
public static void DFS(List<String> res, int left, int right, String curStr, int n)
{//递归终止;将一种组合添加到结果集if (left == n && right == n){res.add(curStr);return;}//尝试使用右括号后,若左括号使用数量小于右括号使用数量,则“剪枝”(否则会违背有效括号的定义)if (left < right)return;//优先使用左括号if (left < n)DFS(res, left + 1, right, curStr + "(", n);//使用右括号if (right < n)DFS(res, left, right + 1, curStr +")", n);
}
广搜
/*** 队列结点*/
class Node
{String curStr;int left;   //左括号还剩几个没用int right; //右括号还剩几个没用public Node(String curStr, int left, int right){this.curStr = curStr;this.left = left;this.right = right;}
}public List<String> generateParenthesis_3(int n)
{//特判,否则n==0时下面的算法会返回""if(n == 0)return null;//结果集ArrayList<String> res = new ArrayList<String>();ArrayDeque<Node> queue = new ArrayDeque<>();//初始结点入队queue.offer(new Node("", n, n));while (!queue.isEmpty()){//队头元素出队Node curNode = queue.poll();//生成了一组有效括号if(curNode.left == 0 && curNode.right == 0)res.add(curNode.curStr);//优先使用左括号if (curNode.left > 0)queue.offer(new Node(curNode.curStr + "(", curNode.left - 1, curNode.right));//左括号少于右括号的情况下,才能使用右括号if (curNode.right > 0 && curNode.left < curNode.right)queue.offer(new Node(curNode.curStr + ")", curNode.left, curNode.right - 1));}return res;
}

最小栈

155. 最小栈 - 力扣(LeetCode)

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

实现 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.

提示:

  • -231 <= val <= 231 - 1
  • poptopgetMin 操作总是在 非空栈 上调用
  • push, pop, top, and getMin最多被调用 3 * 104

建立一个存储val的元素栈和一个辅助栈,辅助栈与元素栈同步push和pop,并存储每个val入栈后对应的最小值

以空间换时间

ArrayDeque<Integer> stack;  //元素栈ArrayDeque<Integer> minStack;   //辅助栈public MinStack()
{stack = new ArrayDeque<>();minStack = new ArrayDeque<>();minStack.push(Integer.MAX_VALUE);
}public void push(int val)
{stack.push(val);minStack.push(Math.min(minStack.peek(), val));
}public void pop()
{stack.pop();minStack.pop();
}public int top()
{return stack.peek();
}public int getMin()
{return minStack.peek();
}

最大栈

716. 最大栈 - 力扣(LeetCode)

题目要求与【最小栈】基本相同,难度提升在于要我们实现**“popMax():检索并返回栈中最大元素,并将其移除。如果有多个最大元素,只要移除最靠近栈顶的那个。”**,以及数据增强,对时间效率要求更高

元素栈+辅助栈

对时间要求不严格的情况下,可以沿用最小栈的解法,并建立一个临时栈实现popMax()

public class MaxStack
{ArrayDeque<Integer> stack;  //元素栈ArrayDeque<Integer> maxStack;   //辅助栈public MaxStack(){stack = new ArrayDeque<>();maxStack = new ArrayDeque<>();maxStack.push(Integer.MIN_VALUE);}public void push(int x){stack.push(x);maxStack.push(Math.max(maxStack.peek(), x));}public int pop(){maxStack.pop();return stack.pop();}public int top(){return stack.peek();}public int peekMax(){return maxStack.peek();}public int popMax(){int max = peekMax();ArrayDeque<Integer> tempStack = new ArrayDeque<>();//将元素栈stack中在最大元素之上的所有元素一次倾倒、存储起来。辅助栈需要同步操作while (top() != max )tempStack.push(pop());//找到距离栈顶最近的最大元素,删除它pop();//将临时栈中的元素倒回去while (!tempStack.isEmpty())push(tempStack.pop());return max;}
}
用链表结点同时存储val和max

逻辑与第一种解法一致,但一样无法通过最后一个严格的测试用例

class Node
{int val;    //元素的值int max;    //此时的最大值Node next;public Node(int val, int max, Node next) {this.val = val;this.max = max;this.next = next;}
}class MaxStack_2
{Node head = null;  //指向表首元素public MaxStack_2(){}public void push(int x){if (head == null)head = new Node(x, x, null);else    //x与之前的最大值比较,得出新的最大值head = new Node(x, Math.max(head.max, x), head);}public int pop(){int val = head.val;head = head.next;return val;}public int top(){return head.val;}public int peekMax(){return head.max;}public int popMax(){int Max = head.max;Node tempList = null;   //临时链表的头指针,作用与临时栈的栈顶指针相同while (head.val != Max){Node suc = head.next;head.next = tempList;tempList = head;head = suc;}//删除最大元素head = head.next;//“倒回去”while (tempList != null){push(tempList.val);tempList = tempList.next;}return Max;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024.1.4每日一题

LeetCode每日一题 2397.被列覆盖的最多行数 2397. 被列覆盖的最多行数 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你一个下标从 0 开始、大小为 m x n 的二进制矩阵 matrix &#xff1b;另给你一个整数 numSelect&#xff0c;表示你必须从 matrix 中选择的 不同 …

vue3 插槽 slot 使用

vue3 插槽 slot 使用 在 Vue3 中&#xff0c;插槽&#xff08;slot&#xff09;是一种重要的组件复用和内容分发机制。通过使用插槽&#xff0c;可以让组件更加灵活和具有可复用性&#xff0c;在不同的地方渲染不同的内容&#xff0c;同时保证相同的样式。 插槽资料 官网介绍&…

freertos——任务通知知识总结与任务通知模拟及信号量实验、消息邮箱实验、事件标志组实验

1.任务通知概念 任务通知&#xff1a;用来通知任务的&#xff0c;任务控制块中的结构体成员变量 ulNotifiedValue就是这个通知值&#xff0c;不需要另外创建一个结构体可以直接接受别人发过来的通知 2.任务通知的优势及劣势 任务通知的优势&#xff1a; 效率更高 &#xff…

Android开发中“真正”的仓库模式

原文地址&#xff1a;https://proandroiddev.com/the-real-repository-pattern-in-android-efba8662b754原文发表日期&#xff1a;2019.9.5作者&#xff1a;Denis Brandi翻译&#xff1a;tommwq翻译日期&#xff1a;2024.1.3 Figure 1: 仓库模式 多年来我见过很多仓库模式的实…

Vue 单文件组件的基础入门指南

本文是我2年前做的一个学习小demo&#xff0c;在这里分享一下 希望对想要学习Vue的小伙伴能有一丢丢的小帮助~_~ 1 Vue CLI Vue CLI (opens new window)是一个基于Vue.js进行快速开发的完整系统。 这里我使用 Vue CLI 生成了一个Vue项目&#xff0c;命令为&#xff1a;vue cr…

C语言中指针变量如何使用

一、指针变量的定义与声明 1.1 定义 指针变量是用来存储另一个变量的内存地址的变量。在C语言中&#xff0c;指针变量的类型是指向某个类型的指针。例如&#xff0c;int *p; 表示一个整型指针变量p。 1.2 声明 指针变量的声明分为两种形式&#xff0c;一种是直接声明&#…

字节跳动 Spark 支持万卡模型推理实践

摘要&#xff1a;本文整理自字节跳动基础架构工程师刘畅和字节跳动机器学习系统工程师张永强在本次 CommunityOverCode Asia 2023 中的《字节跳动 Spark 支持万卡模型推理实践》主题演讲。 背景介绍 在云原生化的发展过程中 Kubernetes 由于其强大的生态构建能力和影响力&…

多线程基础入门【Linux之旅】——下篇【死锁,条件变量,生产消费者模型,信号量】

目录 一&#xff0c;死锁 1. 死锁的必要条件 2&#xff0c;避免死锁 二&#xff0c;条件变量 同步概念与竞态条件 条件变量——初始化 静态初始化 动态初始化 pthread_cond_destroy (销毁) pthread_cond_wait (等待条件满足) pthread_cond_signal (唤醒线程) ph…

2023 北京国炬软件年度总结—JeecgBoot与敲敲云

2023年对于北京国炬软件公司来说是一个充满成就和创新的一年。 我们成功推出了APass零代码平台—敲敲云&#xff0c;一款能够在5分钟内搭建应用的新一代零代码平台。自2023年1月1号正式上线以来&#xff0c;敲敲云已经突破了10万注册用户&#xff0c;并与数百家战略合作伙伴达…

Rust使用gRPC

需要先安装protoc&#xff08;Protocol Buffers Compiler&#xff09;&#xff0c;可据此Protobuf Compiler Installation下载 第一步&#xff1a;创建项目 创建两个新的Rust项目&#xff0c;分别作为服务端与客户端&#xff1a; cargo new rust_grpc_servercargo new rust_grp…

【python测验】数字游戏 取模数 数位dp

这题目看得人感觉要失去梦想…… 题目&#xff1a; 看不懂也做不出来&#xff0c;python方法未知&#xff0c;记录几个可供参考的帖子。 LightOJ 1068 Investigation 算法提高篇–动态规划&#xff08;八&#xff09;&#xff1a;数位DP&#xff08;3&#xff09;

【软件测试】2024年准备中/高级测试岗技术面试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、软件测试基础知…