日撸Java三百行(day15:栈的应用之括号匹配)
目录
一、栈的括号匹配
二、代码实现
1.方法创建
2.数据测试
3.完整的程序代码
总结
一、栈的括号匹配
要完成今天的任务,需要先来了解一下什么是栈的括号匹配。首先,顾名思义,括号匹配就是指将一对括号匹配起来,我们给定一个字符串(字符串中除了各类括号,也可以有别的字符),将字符串中的所有括号都根据规则:对应的一对左括号与右括号按“先左后右”的顺序匹配起来,这个过程即为括号匹配。
在判断括号匹配时,需要注意一些细节:
- 必须是对应的一对左括号与右括号,即“( ”与“ )”对应,“ [ ”与“ ] ”对应,“ { ”与“ } ”对应。
- 必须是“一左一右”,不能两个均为左括号或者两个均为右括号,即“( ”与“ )”可以匹配,但是“( ”与“( ”不匹配,“ )”与“ )”也不匹配。
- 必须按“先左后右”的顺序,即“( )”匹配,但是“ )( ”就不匹配。
- 括号匹配遵循就近原则,以当前括号的左边第一个括号为准。比如在下面的字符串中,设第6个括号为当前括号,那么就以该括号左边第一个括号为准,即以第5个括号为准,所以5、6成功匹配。可以看到,在下图中第6个括号与第3个括号也满足了以上三个基本条件,但是因为就近原则的存在,所以3、6不匹配。同理,如果第5个括号改为了“ [ ”或者“ { ”,那么5、6也不会匹配。

- 括号匹配遵循匹配消除原则,一旦某一对括号匹配成功,那么该对括号就“消除”,继续匹配后面的括号。比如在上图中,5、6成功匹配后“消除”,然后4、7继续匹配,再比如“ { [ ( ) ] } ”也是匹配的。
- 所给字符串中的全部括号都匹配成功才算完成了括号匹配,比如“ [ { ( [ ( ) ] ) } ] ”是匹配的,但是“ ( [ { ( [ ] ) ] ] ) ”就不匹配。
- 在所给的字符串中,除了各类括号,也可以有别的字符,比如“ 10 / { [ 4 - ( 5 - 2 ) ] * 2 } ”也是匹配的。
二、代码实现
弄清楚基本概念后,就可以进行代码实现了。根据“先左后右”的顺序要求以及匹配消除原则,我们可以按如下步骤进行括号匹配(因为别的非括号字符对于括号匹配不起任何作用,所以直接视为透明就行):
- 遇到左括号“( ”、“ [ ”、“ { ”就直接入栈,在栈中存放
- 遇到右括号“ )”、“ ] ”、“ } ”就从栈中弹出栈顶元素,与该右括号进行匹配,如果二者匹配成功就“消除”,继续匹配后面的括号;如果二者匹配不成功,直接输出不匹配即可
不过,需要注意一点,由于要求的是字符串中的全部括号均匹配才算成功,所以如果匹配完毕后发现栈中仍然还存在左括号或者栈不空,那么也算作匹配失败。
对于这个问题,我们当然可以选择在匹配完毕后直接判断栈是否为空,但是我们也可以采取另一种方式:即在进行括号匹配之前,入栈一个非括号字符作为栈底元素,再在匹配完毕后进行出栈操作,判断此时出栈的元素是否为该非括号字符,如果是,则说明字符串中的全部括号均已匹配;如果不是,则直接返回不匹配。
1.方法创建
进行代码模拟时,我们只需要在昨天的代码基础上增加一个括号匹配的方法即可,如下:
/************************ Is the bracket matching?* * @param paraString The given expression.* @return Match or not.**********************/public static boolean bracketMatching(String paraString) {// Step 1. Initialize the stack through pushing a '#' at the bottom.CharStack tempStack = new CharStack();tempStack.push('#');char tempChar, tempPoppedChar;// Step 2. Process the string. For a string, length() is a method// instead of a member variable.for(int i = 0; i < paraString.length(); i++) {tempChar = paraString.charAt(i);switch(tempChar) {case '(':case '[':case '{':tempStack.push(tempChar);break;case ')':tempPoppedChar = tempStack.pop();if(tempPoppedChar != '(') {return false;} // of ifbreak;case ']':tempPoppedChar = tempStack.pop();if(tempPoppedChar != '[') {return false;} // of ifbreak;case '}':tempPoppedChar = tempStack.pop();if(tempPoppedChar != '{') {return false;} // of ifbreak;default:// Do nothing} // of switch} // of for itempPoppedChar = tempStack.pop();if(tempPoppedChar != '#') {return false;} // of ifreturn true;} // of bracketMatching
首先,定义括号匹配的方法bracketMatching,其中String类型的参数paraString即为要输入的字符串,再创建一个栈,并入栈一个'#',将'#' 作为栈底的非括号字符。
然后,利用charAt()方法+for循环,将字符串中的字符一个一个读取出来。
补充:
length()方法:作用是返回字符串的长度,调用格式为字符串名.length()
charAt()方法:作用是获取字符串中指定索引值的字符,调用格式为字符串名.charAt(指定索引值)
根据之前的分析,这里需要进行读取字符的判断,且判断分支较多,符合switch语句适用的情况(单一变量的多个不同取值问题),所以我们采用了switch语句。
匹配完毕后,进行出栈操作,并判断此时出栈的元素是否为'#',如果不是则直接返回false;如果是,则返回true。
2.数据测试
下面我们进行数据测试,这里用到了以下五个数据:
- [ 2 + (1 - 3) ] * 4
- ( ) )
- ( ) ( ) ( ( ) )
- ( { } [ ] )
- ) (
显然,通过直接思考可以预测第1、3、4个字符串是匹配的,剩下的是不匹配的。
/************************The entrance of the program.** @param args Not used now.**********************/public static void main(String[] args) {CharStack tempStack = new CharStack();for(char ch = 'a'; ch < 'm'; ch++) {tempStack.push(ch);System.out.println("The current stack is: " + tempStack);} // of for chchar tempChar;for(int i = 0; i < 12; i++) {tempChar = tempStack.pop();System.out.println("Popped: " + tempChar);System.out.println("The current stack is: " + tempStack);} // of for iboolean tempMatch;String tempExpression = "[2 + (1 - 3)] * 4";tempMatch = bracketMatching(tempExpression);System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);tempExpression = "( ) )";tempMatch = bracketMatching(tempExpression);System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);tempExpression = "()()(())";tempMatch = bracketMatching(tempExpression);System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);tempExpression = "({}[])";tempMatch = bracketMatching(tempExpression);System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);tempExpression = ")(";tempMatch = bracketMatching(tempExpression);System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);} // of main
3.完整的程序代码
package datastructure;/***Char stack. I do not use Stack because it is already defined in Java.**@auther Xin Lin 3101540094@qq.com.*/public class CharStack {/*** The depth.*/public static final int MAX_DEPTH = 10;/*** The actual depth.*/int depth;/*** The data.*/char[] data;/************************ Construct an empty char stack.**********************/public CharStack() {depth = 0;data = new char[MAX_DEPTH];} // of the first constructor/************************ Overrides the method claimed in Object, the superclass of any class.**********************/public String toString() {String resultString = "";for (int i = 0; i < depth; i++) {resultString += data[i];} // of for ireturn resultString;} // of toString/************************ Push an element.* * @param paraChar The given char.* @return Success or not.**********************/public boolean push(char paraChar) {if (depth == MAX_DEPTH) {System.out.println("Stack full.");return false;} // of ifdata[depth] = paraChar;depth++;return true;} // of push/************************ Pop an element.* * @return The popped char.**********************/public char pop() {if(depth == 0) {System.out.println("Nothing to pop.");return '\0';} // of ifchar resultChar = data[depth - 1];depth--;return resultChar;} // of pop/************************ Is the bracket matching?* * @param paraString The given expression.* @return Match or not.**********************/public static boolean bracketMatching(String paraString) {// Step 1. Initialize the stack through pushing a '#' at the bottom.CharStack tempStack = new CharStack();tempStack.push('#');char tempChar, tempPoppedChar;// Step 2. Process the string. For a string, length() is a method// instead of a member variable.for(int i = 0; i < paraString.length(); i++) {tempChar = paraString.charAt(i);switch(tempChar) {case '(':case '[':case '{':tempStack.push(tempChar);break;case ')':tempPoppedChar = tempStack.pop();if(tempPoppedChar != '(') {return false;} // of ifbreak;case ']':tempPoppedChar = tempStack.pop();if(tempPoppedChar != '[') {return false;} // of ifbreak;case '}':tempPoppedChar = tempStack.pop();if(tempPoppedChar != '{') {return false;} // of ifbreak;default:// Do nothing} // of switch} // of for itempPoppedChar = tempStack.pop();if(tempPoppedChar != '#') {return false;} // of ifreturn true;} // of bracketMatching/************************The entrance of the program.** @param args Not used now.**********************/public static void main(String[] args) {CharStack tempStack = new CharStack();for(char ch = 'a'; ch < 'm'; ch++) {tempStack.push(ch);System.out.println("The current stack is: " + tempStack);} // of for chchar tempChar;for(int i = 0; i < 12; i++) {tempChar = tempStack.pop();System.out.println("Popped: " + tempChar);System.out.println("The current stack is: " + tempStack);} // of for iboolean tempMatch;String tempExpression = "[2 + (1 - 3)] * 4";tempMatch = bracketMatching(tempExpression);System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);tempExpression = "( ) )";tempMatch = bracketMatching(tempExpression);System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);tempExpression = "()()(())";tempMatch = bracketMatching(tempExpression);System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);tempExpression = "({}[])";tempMatch = bracketMatching(tempExpression);System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);tempExpression = ")(";tempMatch = bracketMatching(tempExpression);System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);} // of main
} // of class CharStack
运行结果:

可以发现运行结果与我们之前的预测是完全相同的。
总结
总体来说,今天学习的内容不是很复杂,简单来说就是对昨天栈的入栈出栈等操作进行一个应用,而且根据今天代码的难度,其实可以知道括号匹配算是栈的一个基本应用,不过它也是一个非常重要的应用,在今后很多算法和问题中都会涉及到。
相关文章:
日撸Java三百行(day15:栈的应用之括号匹配)
目录 一、栈的括号匹配 二、代码实现 1.方法创建 2.数据测试 3.完整的程序代码 总结 一、栈的括号匹配 要完成今天的任务,需要先来了解一下什么是栈的括号匹配。首先,顾名思义,括号匹配就是指将一对括号匹配起来,我们给定一…...
Oracle-OracleConnector
提示:OracleConnector 类是 Debezium 中用于与 Oracle 数据库交互的一个连接器组件 文章目录 前言一、核心功能二、代码分析总结 前言 提示:OracleConnector 类负责配置、启动、管理和验证与 Oracle 数据库的连接,并为后续的数据捕获任务准备…...
『 Linux 』线程池与 POSIX 线程的封装编码实现
文章目录 线程池概念线程池的编码实现线程池的测试参考代码 线程的封装使用测试封装后的线程参考代码 线程池概念 池化技术是一种资源管理方法,通过预先创建和管理一组资源以便在需要使用时快速分配这些资源; 线程池是池化技术的一种典型应用; 资源分配 在线程池中预先创建一定…...
【C++】————哈希表
作者主页: 作者主页 本篇博客专栏:C 创作时间 :2024年8月6日 前言: 在计算机科学的广袤世界中,数据结构犹如基石,支撑着各种高效算法的构建与运行。而哈希表(Hash Table)&#…...
前端学习AI历程
AI基本概念tensorflow入门conda搭建环境,pycham使用训练自己的第一个模型AI目前前端方便入手的几个方向 素材图片库图像识别,在线学习低代码应用智能客服 获取数据集 roboflowkagglecocomakesense(用于打标) 认识yolo两个简单小应…...
常见中间件漏洞复现之【Tomcat】!
Tomcat介绍 tomcat是⼀个开源⽽且免费的jsp服务器,默认端⼝ : 8080,属于轻量级应⽤服务器。它可以实现 JavaWeb程序的装载,是配置JSP(Java Server Page)和JAVA系统必备的⼀款环境。 在历史上也披露出来了很多的漏洞 …...
C++并发编程(一):线程基础
简介 本文学习的是 b 站 up 恋恋风辰的并发编程教学视频做的一些笔记补充。 教程视频链接如下:线程基础:视频教程 文档链接如下:线程基础:笔记文档 理论上直接看 up 提供的笔记文档即可,我这里主要是记录一些我自己…...
enq: HW - contention事件来啦
业务系统反应数据库慢,根据时间查看awr报告。 先看一眼事件名称 HW enqueue 用于序列化超出段高水位线的空间分配。如果同时向对象添加大量数据,则多个进程可能同时尝试在高水位线上方分配空间,从而导致争用。 既然是控制资源并发的enq&…...
MyBatis补充
控制类和dao层接口以及mapper中的xml是怎样的关联的? 在Mybatis中,控制类和dao层接口是通过mapper的xml文件进行连接的。 控制类调用dao层接口中的方法,通过接口实现进行访问数据库操作。dao层接口定义数据库操作的方法,提供给控制…...
系统架构师(每日一练16)
每日一练 答案与解析 1.软件测试一般分为两个大类:动态测试和静态测试。前者通过运行程序发现错误,包括()等方法;后者采用人工和计算机辅助静态分析的手段对程序进行检测,包括()等方法。答案与解析 问题1 A.边界值分析、逻辑覆盖、基本路径 B.桌面检查、…...
实践致知第17享:电脑忽然黑屏的常见原因及处理方法
一、背景需求 小姑电话说:最近,电脑忽然就黑屏了(如下图所示),但是等待几十秒甚至一分钟,电脑就能自然恢复了,这种状况一天能出现三四次,怎么办? 二、分析诊断 电脑黑屏…...
微信小程序--实现地图定位---获取经纬度
(1) (2) (3) html: <view class"titleTwo" style"border: none;"><view class"fontSize30 invoiceTile">企业地址</view><view class"invoiceRight" bind:tap"tapChooseAddress" data-maptype"…...
【Python系列】使用 `isinstance()` 替代 `type()` 函数
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
【多模态大模型】 BLIP-2 in ICML 2023
一、引言 论文: BLIP-2: Bootstrapping Language-Image Pre-training with Frozen Image Encoders and Large Language Models 作者: Salesforce Research 代码: BLIP-2 特点: 该方法分别使用冻结的图像编码器(ViT-L/…...
HPC高性能计算平台
随着技术的发展和数据量的爆炸性增长,企业面临的挑战日益复杂,对计算能力的需求也在不断增加。这些问题的解决超出了传统计算方法的能力范围,高性能计算(HPC)正是为解决这类问题而生。 高性能计算(HPC&…...
前端常用的几个工具网站
觉得不错的前端工具类网站 1、Grid布局生成 https://cssgrid-generator.netlify.app 2、拟物按钮样式生成 https://neumorphism.io 3、玻璃形态效果 在线制作CSS玻璃形态 4、一些Button、checkBox、switch、card的css样式 零代码 - 精美CSS样式库 5、CSS阴影生成 在线创建…...
支付功能之代收代付
有很多老板问小编:“这个分账功能好是好,也能搞定项目中的二清问题和税务纠纷,但还是太复杂了,每次要添加被分账对象都需要提交材料进行审核,太繁琐了,有没有更方便快捷的支付产品来解决资金问题࿱…...
QPixmap
pixel[ˈpɪksl]像素 QPixmap 是 Qt 框架中用于处理图像的一个类。它主要用于在屏幕上显示和处理图像,提供了许多实用的功能,如加载、保存、缩放、旋转、合并等。 绘制 从文件加载:从指定文件加载图像。 QPixmap pixmap(":/images/exam…...
Laravel门面之下:构建自定义门面应用的艺术
Laravel门面之下:构建自定义门面应用的艺术 在Laravel框架中,门面(Facade)提供了一种将类静态调用与面向对象代码解耦的优雅方式。门面是一个全局可访问的类,它为底层复杂的服务提供了一个简单的接口。然而࿰…...
智启万象 | 2024 Google 开发者大会直播攻略
8 月 7 日上午 9:30 2024 Google 开发者大会 主旨演讲直播将准时开启 想要在线上探索大会精彩内容? 快查收这份观看指南! 8 月 7 日上午 9:30 2024 Google 开发者大会开幕 锁定大会官网观看主旨演讲现场直播! 本次大会内容将同步于多个…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
