每日一题---OJ题: 有效的括号

片头

嗨! 小伙伴们,大家好! 我们又见面啦! 今天我们来一起尝试一下这道题目---有效的括号,准备好了吗? 我们开始咯!

说实话,我刚开始做这道题的时候也是一脸懵,怎么进行括号匹配呢?

别慌,我们一起画个图,分析分析括号匹配的过程~

如下图所示,上方表示一个字符串数组,存放不同种类的左括号和右括号,用一个指针依次遍历字符串中的每一个元素

如果是左括号,则入栈,如果是右括号,则栈顶元素出栈和字符串数组中的元素进行匹配。

第一次:

左括号,则入栈

第二次:

左括号,则入栈

第三次:

左括号,则入栈

 第四次:

此时指针指向的元素为右括号,应该出栈

第五次:

左括号,则入栈

第六次:

右括号,则出栈

 第七次:

右括号,则出栈

第八次:

右括号,则出栈

第九次:

左括号,则入栈

第十次:

右括号,则出栈

第十一次:

左括号,则入栈

第十二次:

右括号,则出栈

好的,这道题的执行过程我们大致分析清楚了,怎么实现呢?

 我们可以利用栈来解答这道题

先定义Stack.h文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int ElemType;
typedef struct Stack {ElemType* arr;		//数组int top;			//栈顶int capacity;		//栈的容量
}Stack;//初始化栈
void StackInit(Stack* ps);
//入栈
void StackPush(Stack* ps,ElemType data);
//出栈
void StackPop(Stack* ps);
//获取栈顶元素
ElemType StackTop(Stack* ps);
//获取栈中有效元素的个数
int StackSize(Stack* ps);
//检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
//销毁栈
void StackDestroy(Stack* ps);

 再定义Stack.c文件

#include"Stack.h"
//初始化栈
void StackInit(Stack* ps) {assert(ps);ps->arr = NULL;ps->capacity = 0;ps->top = 0;
}
//入栈
void StackPush(Stack* ps, ElemType data) {assert(ps);//扩容if (ps->capacity == ps->top) {int newCapacity = ps->capacity == 0 ? 4 : 2 * (ps->capacity);ElemType* temp =(ElemType*) realloc(ps->arr, newCapacity * sizeof(ElemType));if (temp == NULL) {perror("realloc fail!\n");exit(1);}ps->arr = temp;ps->capacity = newCapacity;}ps->arr[ps->top] = data;ps->top++;
}
//出栈
void StackPop(Stack* ps) {assert(ps);assert(!StackEmpty(ps));ps->top--;
}
//获取栈顶元素
ElemType StackTop(Stack* ps) {assert(ps);assert(!StackEmpty(ps));int ret = ps->arr[ps->top - 1];return ret;
}
//获取栈中有效元素的个数
int StackSize(Stack* ps) {assert(ps);return ps->top;
}
//检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps) {assert(ps);return ps->top == 0;	//如果top为0,说明栈为空,返回1
}
//销毁栈
void StackDestroy(Stack* ps) {assert(ps);if (ps->arr) {free(ps->arr);ps->arr = NULL;}ps->capacity = 0;ps->top = 0;
}

最后我们再来测试一下,定义test.c文件

#include"Stack.h"
#include<stdbool.h>
int main() {Stack st;            //定义一个栈StackInit(&st);      //初始化这个栈StackPush(&st, 1);   //将"1"放入栈内StackPush(&st, 2);   //将"2"放入栈内StackPush(&st, 3);   //将"3"放入栈内StackPush(&st, 4);   //将"4"放入栈内StackPush(&st, 5);   //将"5"放入栈内while (!StackEmpty(&st)) {    //如果栈不为空,那么获取栈中的元素int top = StackTop(&st);   //获取栈顶元素printf("%d ", top);        //打印栈顶元素StackPop(&st);            //将栈顶元素删除}StackDestroy(&st);            //销毁栈return 0;
}

运行结果为:

5   4   3   2   1

 OK啦,我们的栈就实现完毕! 接下来我们就可以将它套用到题目中去~

我们刚写了一个栈,直接把 Stack.h 和 Stack.c 复制粘贴过去,把头文件删掉, 再把 typedef int ElemType 改成 typedef char ElemType;

部分代码如下:

typedef char ElemType;        //一定是 char, 不要弄错了,题目要求是字符串数组
typedef struct Stack {ElemType* arr;		//数组int top;			//栈顶int capacity;		//栈的容量
}Stack;//初始化栈
void StackInit(Stack* ps);
//入栈
void StackPush(Stack* ps,ElemType data);
//出栈
void StackPop(Stack* ps);
//获取栈顶元素
ElemType StackTop(Stack* ps);
//获取栈中有效元素的个数
int StackSize(Stack* ps);
//检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
//销毁栈
void StackDestroy(Stack* ps);//初始化栈
void StackInit(Stack* ps) {ps->arr = NULL;ps->capacity = 0;ps->top = 0;
}
//入栈
void StackPush(Stack* ps, ElemType data) {//扩容if (ps->capacity == ps->top) {int newCapacity = ps->capacity == 0 ? 4 : 2 * (ps->capacity);ElemType* temp =(ElemType*) realloc(ps->arr, newCapacity * sizeof(ElemType));if (temp == NULL) {perror("realloc fail!\n");exit(1);}ps->arr = temp;ps->capacity = newCapacity;}ps->arr[ps->top] = data;    //插入数据ps->top++;                  //栈顶向上移动一个单位
}
//出栈
void StackPop(Stack* ps) {assert(ps);assert(!StackEmpty(ps));    //栈不能为空ps->top--;
}
//获取栈顶元素
ElemType StackTop(Stack* ps) {assert(ps);assert(!StackEmpty(ps));//不改变top指针,只是获取栈顶元素int ret = ps->arr[ps->top - 1];return ret;
}
//获取栈中有效元素的个数
int StackSize(Stack* ps) {assert(ps);return ps->top; //top恰好是元素的个数
}
//检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps) {return ps->top == 0;
}
//销毁栈
void StackDestroy(Stack* ps) {assert(ps);if (ps->arr) {free(ps->arr);ps->arr = NULL;}ps->capacity = 0;ps->top = 0;
}

 接下来就是重头戏咯! 小伙伴们可要看仔细咯!

第一步,我们先定义一个栈,然后将这个栈初始化

   Stack st;           //定义一个栈StackInit(&st);     //初始化这个栈

第二步,我们用题目所给的条件: 该方法传递过来的形参s, 类型为char* ,意味着s是一个指向字符串数组的指针,可以遍历整个字符串数组, 因此,当s指针遍历到字符串数组的结束符'\0'的时候,退出循环

和刚刚我们分析的思路一样,当s指针遍历到左括号时,则该元素入栈; s指针遍历到右括号时,将栈里面的元素出栈,看是否匹配; 如果匹配不成功,直接返回false; 接着,s指针继续指向下一个元素。

这里有一个特别容易被忽略的一个点: 当栈为空,且遇到右括号,栈里面没有左括号,销毁栈,返回false

这个部分的代码如下:

//当*s不等于'\0'的时候,进入while循环
while(*s){if(*s == '{' || *s == '[' || *s == '('){//将该元素放入栈内StackPush(&st,*s);}else{//当栈为空,且遇到右括号,栈里面没有左括号,返回falseif(StackEmpty(&st)){//销毁栈,防止内存泄漏StackDestroy(&st);return false;}int top = StackTop(&st);        //获取栈顶元素StackPop(&st);                  //将栈顶元素删除//将栈顶元素和*s进行匹配//如果出栈元素是'(',但是此时的*s不是')',说明不匹配,返回false//如果出栈元素是'[',但是此时的*s不是']',说明不匹配,返回false//如果出栈元素是'{',但是此时的*s不是'}',说明不匹配,返回falseif(top == '(' && *s != ')' || top == '[' && *s != ']' || top == '{' && *s != '}')    {    //销毁栈,防止内存泄漏StackDestroy(&st);return false;}}s++;     //s指针继续指向下一个元素
}

哈哈哈,屏幕前的你以为这样代码就写完了吗? 肯定还没有! 因为还有一种情况我们木有考虑到~

那就是当*s已经走到'\0',但是栈不是空,说明栈里面还有左括号,不合题意, 此时StackEmpty返回false ; 如果栈为空,返回true

部分代码如下:

    bool flag = StackEmpty(&st); //用bool类型的flag变量来接受StackEmpty函数的返回值StackDestroy(&st);           //将栈销毁,归还给系统内存return flag;                 //将结果返回

好啦! 这道题被我们解决啦,整体代码如下:

typedef char ElemType;
typedef struct Stack {ElemType* arr;		//数组int top;			//栈顶int capacity;		//栈的容量
}Stack;//初始化栈
void StackInit(Stack* ps);
//入栈
void StackPush(Stack* ps,ElemType data);
//出栈
void StackPop(Stack* ps);
//获取栈顶元素
ElemType StackTop(Stack* ps);
//获取栈中有效元素的个数
int StackSize(Stack* ps);
//检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
//销毁栈
void StackDestroy(Stack* ps);//初始化栈
void StackInit(Stack* ps) {ps->arr = NULL;ps->capacity = 0;ps->top = 0;
}
//入栈
void StackPush(Stack* ps, ElemType data) {//扩容if (ps->capacity == ps->top) {int newCapacity = ps->capacity == 0 ? 4 : 2 * (ps->capacity);ElemType* temp =(ElemType*) realloc(ps->arr, newCapacity * sizeof(ElemType));if (temp == NULL) {perror("realloc fail!\n");exit(1);}ps->arr = temp;ps->capacity = newCapacity;}ps->arr[ps->top] = data;    //插入数据ps->top++;                  //栈顶向上移动一个单位
}
//出栈
void StackPop(Stack* ps) {assert(ps);assert(!StackEmpty(ps));ps->top--;
}
//获取栈顶元素
ElemType StackTop(Stack* ps) {assert(ps);assert(!StackEmpty(ps));//不改变top指针,只是获取栈顶元素int ret = ps->arr[ps->top - 1];return ret;
}
//获取栈中有效元素的个数
int StackSize(Stack* ps) {assert(ps);return ps->top; //top恰好是元素的个数
}
//检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps) {return ps->top == 0;
}
//销毁栈
void StackDestroy(Stack* ps) {assert(ps);if (ps->arr) {free(ps->arr);ps->arr = NULL;}ps->capacity = 0;ps->top = 0;
}bool isValid(char* s) {Stack st;           //定义一个栈StackInit(&st);     //初始化这个栈//当*s不等于'\0'的时候,进入while循环
while(*s){if(*s == '{' || *s == '[' || *s == '('){//将该元素放入栈内StackPush(&st,*s);}else{//当栈为空,且遇到右括号,栈里面没有左括号,返回falseif(StackEmpty(&st)){//销毁栈,防止内存泄漏StackDestroy(&st);return false;}int top = StackTop(&st);        //获取栈顶元素StackPop(&st);                  //将栈顶元素删除//将栈顶元素和*s进行匹配//如果出栈元素是'(',但是此时的*s不是')',说明不匹配,返回false//如果出栈元素是'[',但是此时的*s不是']',说明不匹配,返回false//如果出栈元素是'{',但是此时的*s不是'}',说明不匹配,返回falseif(top == '(' && *s != ')' || top == '[' && *s != ']' || top == '{' && *s != '}')    {    //销毁栈,防止内存泄漏StackDestroy(&st);return false;}}s++;     //s指针继续指向下一个元素
}bool flag = StackEmpty(&st); //用bool类型的flag变量来接受StackEmpty函数的返回值StackDestroy(&st);           //将栈销毁,归还给系统内存return flag;                 //将结果返回
}

片尾

今天我们学习了一道OJ题---有效的括号,里面包含了栈的一些基础知识,希望看完这篇文章能对友友们有所帮助 !  !  !

点赞收藏加关注 !   !   !

谢谢大家 !   !   !

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

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

相关文章

深入剖析Tomcat(二) 实现一个简单的Servlet容器

现在开始《深入剖析Tomcat》第二章的内容&#xff0c;第一章中&#xff0c;我们编码实现了一个能正常接收HTTP请求并返回静态资源的Web容器&#xff0c;这一章开始引入Servlet的概念&#xff0c;使我们的服务能根据请求动态返回内容。 Servlet是什么&#xff1f; 这是首先要弄…

腾讯EdgeOne产品测评体验——开启安全防护,保障数据无忧

当今时代数字化经济蓬勃发展人们的生活逐渐便利&#xff0c;类似线上购物、线上娱乐、线上会议等数字化的服务如雨后春笋般在全国遍地生长&#xff0c;在人们享受这些服务的同时也面临着各式各样的挑战&#xff0c;如网络数据会不稳定、个人隐私容易暴露、资产信息会被攻击等。…

单链表链表专题

1 链表的概念 概念&#xff1a;链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 链表的结构跟⽕⻋⻋厢相似&#xff0c;淡季时⻋次的⻋厢会相应减少&#xff0c;旺季时⻋次的⻋厢会额外增加⼏节。只 需要…

MySQL表结构的操作

文章目录 1. 创建表2. 查看表3. 修改表4. 删除表 1. 创建表 create table table_name (field1 datatype,field2 datatype,field3 datatype )character set 字符集 collate 校验集 engine 存储引擎;field&#xff1a;列名datatype&#xff1a;列的类型character set&#xff1a…

zookeeper分布式应用程序协调服务+消息中间件kafka分布式数据处理平台

一、zookeeper基本介绍 1.1 zookeeper的概念 Zookeeper是一个开源的分布式的&#xff0c;为分布式框架提供协调服务的Apache项目。 是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件&#xff0c;提供的功能包括&#xff1a;配置维护、域名服务、…

滑动窗口题解2

目录 1 找到字符串中所有字母异位词 分析&#xff1a; 代码展示&#xff1a; 代码展示&#xff1a; 2 串联所有单词的子串 分析&#xff1a; 代码展示&#xff1a; 3 串联所有单词的子串 分析&#xff1a; 代码展示&#xff1a; 4 水果成篮 分析&#xff1a; 代码展…

障碍物识别技术赋能盲人独立出行:一场静默的科技革新

作为一名资深记者&#xff0c;我始终关注并报道那些科技如何助力特殊群体克服生活挑战的动人故事。近期&#xff0c;一款叫做蝙蝠避障的应用进入了我的视线&#xff0c;它搭载先进障碍物识别技术以其独特的优势&#xff0c;悄然为视障人士的独立出行带来了显著变革。 “障碍物识…

一.shell基本知识

目录 1.1为什么学习和使用Shell编程 1.2什么是Shell 1.2.1 shell的起源 1.2.2shell的功能 1.3shell的分类 1.4作为程序设计的语言一—shell 1.5如何学好shell 1.6shell脚本的基本元素 1.7 shell脚本编写规范 1.8 shell脚本的执行方式 1.9 执行脚本的方法 1.10 shel…

ChatGML-6B大模型Windows部署(可CPU运行 保姆级教程)

&#x1f680; 写在最前&#xff1a;这篇文章将学习如何运行ChatGML-6B大模型。 &#x1f680;&#xff1a;点个关注吧&#x1f600;&#xff0c;让我们一起探索计算机的奥秘&#xff01; 一、ChatGML-6B大模型介绍 ChatGML-6B 是一个大型语言模型,被训练来预测人类语言。它是…

人工智能基础部分26-基于知识推理引擎KIE算法的原理介绍与实际应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能基础部分26-基于知识推理引擎KIE算法的原理介绍与实际应用。知识推理引擎(Knowledge Inference Engine, KIE)是一种人工智能技术&#xff0c;其核心原理是基于规则和逻辑的方法来处理复杂的问题。它构建在业…

华为欧拉系统(openEuler-22.03)安装深信服EasyConnect软件(图文详解)

欧拉镜像下载安装 iso镜像官网下载地址 选择最小化安装&#xff0c;标准模式 换华为镜像源 更换华为镜像站&#xff0c;加速下载&#xff1a; sed -i "s#http://repo.openeuler.org#https://mirrors.huaweicloud.com/openeuler#g" /etc/yum.repos.d/openEuler.r…

MongoDB 初识

1.介绍 什么是Mong MongoDB是一种开源的文档型数据库管理系统&#xff0c;它使用类似于JSON的BSON格式&#xff08;Binary JSON&#xff09;来存储数据。与传统关系型数据库不同&#xff0c;MongoDB不使用表和行的结构&#xff0c;而是采用集合&#xff08;Collection&#x…

Leetcode刷题之删除链表中等于给定值 val 的所有结点

Leetcode刷题之删除链表中等于给定值 val 的所有结点 一、题目描述二、题目解析 一、题目描述 Leetcode刷题之删除链表中等于给定值 val 的所有结点 二、题目解析 本题中我们需要将链表中等于val的值的节点删除&#xff0c;首先我想到的方法是通过暴力求解解决&#xff0c;…

递归、搜索与回溯算法:⼆叉树中的深搜

⼆叉树中的深搜 深度优先遍历&#xff08;DFS&#xff0c;全称为 Depth First Traversal&#xff09;&#xff0c;是我们树或者图这样的数据结构中常⽤的 ⼀种遍历算法。这个算法会尽可能深的搜索树或者图的分⽀&#xff0c;直到⼀条路径上的所有节点都被遍历 完毕&#xff…

【Java】maven的生命周期和概念图

maven的生命周期&#xff1a; 在maven中存在三套"生命周期"&#xff0c;每一套生命周期,相互独立,互不影响的,但是中同一套生命周期里,执行后面的命令会自动先执行前面的命令 CleanLifeCycle&#xff1a;清理的生命周期 clean defaultLifeCycle&#xff1a;默认的…

docker-compose yaml指定具体容器网桥ip网段subnet;docker创建即指定subnet;docker取消自启动

1、docker-compose yaml指定具体容器网桥ip网段subnet docker-compose 启动yaml有时可能的容器网段与宿主机的ip冲突导致宿主机上不了网&#xff0c;这时候可以更改yaml指定subnet 宿主机内网一般是192**&#xff0c;这时候容器可以指定172* version: 3.9 services:coredns:…

解锁生成式 AI 的力量:a16z 提供的 16 个企业指南

企业构建和采购生成式AI方面的16项改变 生成式 AI 领域趋势洞察&#xff1a;企业构建和采购生成式 AI 的方式正在发生重大转变&#xff0c;具体表现在&#xff1a;* 专注于可信度和安全性&#xff1a;75% 的企业将信任和安全性视为关键因素。* 优先考虑可扩展性和灵活性&#x…

go语言并发实战——日志收集系统(一) 项目前言

-goroutine- 简介 go并发编程的练手项目 项目背景 一般来说业务系统都有自己的日志,当系统出现问题时,我们一般需要通过日志信息来定位与解决问题&#xff0c;当系统机器较少时我们可以登录服务器来查看,但是当系统机器较多时,我们通过服务器来查看日志的成本就会变得很大,…

状态模式【行为模式C++】

1.概述 状态模式是一种行为设计模式&#xff0c; 让你能在一个对象的内部状态变化时改变其行为&#xff0c; 使其看上去就像改变了自身所属的类一样。 2.结构 State(抽象状态类)&#xff1a;定义一个接口用来封装与上下文类的一个特定状态相关的行为&#xff0c;可以有一个或多…