LeetCode | 20.有效的括号
这次来写一下 LeetCode 的第 20 题,有效的括号。
题目描述
题目直接从 LeetCode 上截图过来,题目如下:
上面的题就是 有效的括号 题目的截图,同时 LeetCode 给出了一个函数的定义,然后要求实现 有效的括号 的函数体。函数定义如下:
bool isValid(char* s) {
}
从上面函数的定义来看,参数是一个字符串,字符串中保存了括号的序列。
问题分析
这个题目是要判断括号是否前后匹配出现,解决这种问题思路是通过数据结构的 “栈” 来进行。
我们常用的括号基本就是 小括号、中括号 和 大括号 这三种。正常情况下,写括号的时候,都会先写开始部分的 “(” 、“[” 或 “{”,然后才成对出现的 “)”、“]” 或 “}” 闭合部分。这几种形式的括号也是题目一开始就明确给出的。
那么,当我们遇到开始部分的三种形式的括号的时候,就让它们入栈,当遇到闭合括号的时候,就取出栈顶的括号来进行匹配,如果它们是配对的,就继续取下一个括号,如果是不配对的,就说明整个括号序列写法是有误的。
举个例子,比如给出的括号字符串是“{[]}”,我们要如何进行判断呢?如图所示。
从图中可以看出,遇到开始的括号就入栈,遇到闭合的括号就把栈顶的拿出来进行匹配。题目中给出的示例 1、2 和 5,都可以通过此方式进行匹配,可以手动画图思考。
如果是类似示例 3 和 4 的情况,其实也是这种方式的,用示例 4 来画图,如图所示。
可以看到,第三个括号是一个 “)” 闭合括号,但是此时栈顶的括号是 “[”,它们是不匹配的,因此这个括号序列是无效的。
代码实现
依据我的思路来写代码,代码还是比较简单的,代码如下:
bool isValid(char* s) {
int len = strlen(s);
int i;
// 栈顶位置
int pos = 0;
char *pArr = (char*)malloc(len * sizeof(char));
for (i = 0; i < len; i ++) {
if (s[i] == '(' || s[i] == '[' || s[i] == '{') {
pArr[pos ++] = s[i];
}
if (s[i] == ')') {
if ( pos - 1 < 0 || pArr[pos - 1] != '(' ) {
return 0;
} else {
pos--;
}
} else if (s[i] == '}') {
if ( pos - 1 < 0 || pArr[pos - 1] != '{' ) {
return 0;
} else {
pos--;
}
} else if (s[i] == ']') {
if ( pos - 1 < 0 || pArr[pos - 1] != '[' ) {
return 0;
} else {
pos--;
}
}
}
free(pArr);
if ( pos != 0 ) {
return 0;
}
return 1;
}
代码不复杂,其中关键的就是 pos 变量表示的是栈顶的位置。只要遇到开始括号则入栈。如果是闭合括号则有三种可能的情况:
第一种情况是,如果此时栈空,则说明没有和它匹配的开始括号,那么它就不是有效的括号序列;
第二种情况是,如果栈不空,但是栈顶的开始括号与它不匹配,那么也说明它不是有效的括号序列;
第三种情况是,栈顶的开始括号与它匹配,此时就调整栈顶的位置,因为下次再需要匹配开始括号的时候,刚才匹配过的就不再匹配了。也就是说,被匹配过的开始括号已经出栈了。
最后循环遍历完所有的括号后,判断栈是否为空,如果全部匹配,那么栈应该是空的,如果栈不为空,说明有开始括号没有被闭合。
提交结果
在写完 isValid 函数体后,点击右下角的 “执行代码”,然后观察 “输出” 和 “预期结果” 是否一致,一致的话就点击 “提交” 按钮。点击 “提交” 按钮后,系统会使用更多的测试用例来测试我们写的函数体,如果所有的测试用例都通过了,那么就会给出 “通过” 的字样,如果没有通过,会给出失败的那一组测试用例,我们继续修改代码。我们以上代码 “提交” 以后的截图如下:
以上代码我认为其实可以有改进的地方,比如括号的长度如果是单数,则直接说明是无效的括号序列。malloc 申请内存空间来当作栈使用时,申请的空间是字符串长度的一半,如果超过这个长度了还要继续入栈,则说明后面的闭合括号肯定无法全部闭合掉前面的开始括号了。可以把入栈的代码放到比较闭合括号代码的后面。不过这些思路我没有挨个去测试。
这个题目还是比较简单的,至少没有什么坑在里面。
- WPF中ListView如何改变选中条背景颜色
- WPF Trigger for IsSelected in a DataTemplate for ListBox items
- C#基础知识回顾--BackgroundWorker介绍
- Elasticsearch 瞬间入门
- 使用OpenLDAP 操作 Windows Active Directory
- 优化算法:到底是数学还是代码?
- Email 服务器之 SPF 记录
- WPF中播放声音媒体文件
- 设计模式学习--装饰者模式(Decorator Pattern)
- SQL Server 存储过程
- MySQL 转换 latin1 到 UTF-8
- C#/ASP.NET应用程序配置文件app.config/web.config的增、删、改操作
- Spring boot with Email
- 使用TensorFlow动手实现的简单的股价预测模型
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 分布式系统的概念都搞懂了吗?(上)
- Kafka-manager部署与使用简单介绍
- 面向对象的7种设计原则(5)-里氏代换原则
- CentOS7下利用Google Authenticator实现SSH登录的二次身份验证
- 满分室间质评之GATK Somatic SNV+Indel+CNV+SV(下)性能优化
- poiAndEasyExcel学习(六)
- C++ 模板沉思录(上)
- Python 为什么会有个奇怪的“...”对象?
- 老板让我从几百个Excel中查找数据,我用Python一分钟搞定!
- 爬取B站20万+条弹幕,我学会了如何成为B站老司机
- Pytorch实现卷积神经网络训练量化(QAT)
- VBA解压缩ZIP文件11——存在问题
- 算法集锦(14)|图像识别| 图像识别算法的罗夏测试
- CenterNet骨干网络之hourglass
- 语音识别中的声学特征提取:梅尔频率倒谱系数MFCC | 老炮儿改名PPLOVELL | 5th