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

news2024/11/15 12:03:10

片头

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

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

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

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

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

第一次:

左括号,则入栈

第二次:

左括号,则入栈

第三次:

左括号,则入栈

 第四次:

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

第五次:

左括号,则入栈

第六次:

右括号,则出栈

 第七次:

右括号,则出栈

第八次:

右括号,则出栈

第九次:

左括号,则入栈

第十次:

右括号,则出栈

第十一次:

左括号,则入栈

第十二次:

右括号,则出栈

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

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

先定义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{
        //当栈为空,且遇到右括号,栈里面没有左括号,返回false
        if(StackEmpty(&st)){
        //销毁栈,防止内存泄漏
            StackDestroy(&st);
           return false;
         }

        int top = StackTop(&st);        //获取栈顶元素
        StackPop(&st);                  //将栈顶元素删除

 //将栈顶元素和*s进行匹配
 //如果出栈元素是'(',但是此时的*s不是')',说明不匹配,返回false
 //如果出栈元素是'[',但是此时的*s不是']',说明不匹配,返回false
 //如果出栈元素是'{',但是此时的*s不是'}',说明不匹配,返回false

        if(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{
        //当栈为空,且遇到右括号,栈里面没有左括号,返回false
        if(StackEmpty(&st)){
        //销毁栈,防止内存泄漏
            StackDestroy(&st);
           return false;
         }

        int top = StackTop(&st);        //获取栈顶元素
        StackPop(&st);                  //将栈顶元素删除

 //将栈顶元素和*s进行匹配
 //如果出栈元素是'(',但是此时的*s不是')',说明不匹配,返回false
 //如果出栈元素是'[',但是此时的*s不是']',说明不匹配,返回false
 //如果出栈元素是'{',但是此时的*s不是'}',说明不匹配,返回false

        if(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.coloradmin.cn/o/1597102.html

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

相关文章

hadoop最新详细版安装教程 2024 最新版

文章目录 hadoop安装教程 2024最新版提前准备工作用户配置安装 SSH Server免密登录设置编辑 SSH server 配置文件配置Java环境查看java 版本验证 环境变量设置安装Hadoop下载hadoop解压hadoop查看hadoop 版本hadoop 配置编辑编辑配置文件core-site.xml编辑配置文件hdfs-site.xm…

gma 2 用户文档(pdf版)更新计划

随着 gma 2 整体构建完成&#xff0c;下一步继续针对库内所有功能完成一个用户指南&#xff08;非网站&#xff09;。相较于上次更新用户文档pdf版&#xff0c;已经过去了大半年。当然&#xff0c;PDF 版比网站上内容更丰富&#xff0c;也更新&#xff08;文档基于 gma 2.0.9a2…

Spring Cloud Gateway详细介绍以及实现动态路由

一. 简介 Spring Cloud Gateway This project provides a libraries for building an API Gateway on top of Spring WebFlux or Spring WebMVC. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to …

【读书笔记】自动驾驶与机器人中的SLAM技术——高翔

文章会对本书第五章节及以后章节进行总结概括。每日更新一部分。一起读书吧。 第五章——基础点云处理 重点&#xff1a;点云的相邻关系是许多算法的基础 5.1 激光雷达传感器与点云的数学模型 5.1.1激光雷达传感器的数学模型 雷达有两种&#xff1a;机械旋转式激光雷达&…

018——红外遥控模块驱动开发(基于HS0038和I.MX6uLL)

目录 一、 模块介绍 1.1 简介 1.2 协议 二、 驱动代码 三、 应用代码 四、 实验 五、 程序优化 一、 模块介绍 1.1 简介 红外遥控被广泛应用于家用电器、工业控制和智能仪器系统中&#xff0c;像我们熟知的有电视机盒子遥控器、空调遥控器。红外遥控器系统分为发送端和…

RISCV指令集体系简读之RV32M

RV32M向RV32I中添加了整数乘法和除法指令&#xff1b; RV32M具有有符号和无符号整数的除法指令&#xff1a;divide(div)和divide unsigned(divu)&#xff0c;它们将 商放入目标寄存器。在少数情况下&#xff0c;程序员需要余数而不是商&#xff0c;因此RV32M提供 remainder(rem…

46.HarmonyOS鸿蒙系统 App(ArkUI)网格布局

Grid(){GridItem(){Button(按钮1).fontSize(28)}.backgroundColor(Color.Blue)GridItem(){Text(数学).fontSize(28)}.backgroundColor(Color.Yellow)GridItem(){Text(语文).fontSize(28)}.backgroundColor(Color.Green)GridItem(){Text(英语).fontSize(28)}.backgroundColor(Co…

结构型模式--3.组合模式【草帽大船团】

1. 好大一棵树 路飞在德雷斯罗萨打败多弗朗明哥之后&#xff0c;一些被路飞解救的海贼团自愿加入路飞麾下&#xff0c;自此组成了草帽大船团&#xff0c;旗下有7为船长&#xff0c;分别是&#xff1a; 俊美海贼团75人 巴托俱乐部56人 八宝水军1000人 艾迪欧海贼团4人 咚塔塔海…

暴雨信息专场推介会亮相武汉国际创科展

4月14日&#xff0c;暴雨信息专场推介会亮相2024年武汉国际创科展。推介会以“智慧聚变新生”为主题&#xff0c;集中展示推介暴雨信息旗下多项颇具市场优势的智能化产品和解决方案&#xff0c;邀请多位专家分享在数字化转型领域的成果和实践经验&#xff0c;与业界同仁共同探讨…

osg渲染过程

目录 1、渲染最简单代码 2、详解run方法 3、详细过程 4、回调函数 5、Node Visitor 1、渲染最简单代码 2、详解run方法 3、详细过程 3.1 advance()方法 进行帧计数 3.2 eventTraversal() eventTraversal()响应用户操作,eventTraversal()遍历的是事件队列&#xff0c;而…

Java开发从入门到精通(二十):Java的面向对象编程OOP:Collection集合框架

Java大数据开发和安全开发 &#xff08;一&#xff09;Java的集合进阶1.1 集合体系结构1.2 Collection集合1.2.1 Collection集合包含哪些接口和实现类1.2.2 Collection集合特点1.2.3 为啥要先学Collection的常用方法?1.2.4 Collection集合的遍历1.2.4.1 迭代器1.2.4.1.1 迭代器…

基于SpringBoot+Vue实现的医院在线挂号系统(代码+万字文档)

系统介绍 基于SpringBootVue实现的医院在线挂号系统设计了三种角色&#xff0c;分别是管理员、医生、用户&#xff0c;每种角色对应不同的菜单 系统实现了个人信息管理、基础数据管理、论坛管理、用户管理、单页数据管理、医生管理及轮播图管理等功能模块&#xff0c;具体功能…

16.读取指定路径下的txt文档然后合并内容为一个txt文档。

1.题目要求 分别读取路径为 ./middle/phone/base/1_student_0.txt, ./middle/vr/base/1_teacher.txt, ./nearby/phone/base/1_student_0.txt, ./nearby/vr/base/1_teacher.txt, ./outside/phone/base/1_student_0.txt, ./outside/vr/base/1_teacher.txt 里面的文件&#xff…

【LeetCode: 3117. 划分数组得到最小的值之和 + 动态规划】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

linux shell脚本编写(2)

Shell: 命令转换器&#xff0c;高级语言转换成二进制语言。是Linux的一个外壳&#xff0c;它包在Lniux内核的外面&#xff0c;用户和内核之间的交互提供了一个接口。 内置命令&#xff1a;在shell内部不需要shell编辑 外置命令&#xff1a;高级语言要用shell转换成二进制语言 …

Numpy数组和列表list的区别

参考&#xff1a;Numpy Array vs List 在Python编程中&#xff0c;列表&#xff08;list&#xff09;和Numpy数组&#xff08;numpy array&#xff09;是两种常见的数据结构&#xff0c;它们都可以用来存储多个元素。但是它们在实际使用中有很大的区别&#xff0c;本文将详细比…

【尚硅谷】Git与GitLab的企业实战 学习笔记

目录 第1章 Git概述 1. 何为版本控制 2. 为什么需要版本控制 3. 版本控制工具 4. Git简史 5. Git工作机制 6. Git和代码托管中心 第2章 Git安装 第3章 Git常用命令 1. 设置用户签名 1.1 基本语法 1.2 案例实操 2. 初始化本地库 2.1 基本语法 2.2 案例实操 3. 查…

RabbbitMQ基本使用及其五种工作模型

初识MQ 同步通讯和异步通讯 什么是同步通讯呢&#xff1f;举个例子&#xff0c;你认识了一个小姐姐&#xff0c;聊的很火热&#xff0c;于是你们慢慢开始打电话&#xff0c;视频聊天&#xff0c;这种方式就成为同步通讯&#xff0c;那什么是一部通讯呢&#xff0c;同样的&…

P1706 全排列问题

原题链接:全排列问题 - 洛谷 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 dfs典题 3. 代码实现 #define _CRT_SECURE_NO_WARNINGS 1 #include<bits/stdc.h> using namespace std; #define ll long long #define endl \n const int N 2…

电脑技巧:Bandicam班迪录屏介绍

目录 一、 软件简介 二、软件功能 2.1 屏幕录制 2.2 游戏录制 2.3 设备录制 2.4实时编辑与截图 2.5 轻量级软件 三、软件用途 3.1 教育培训 3.2 游戏直播与分享 3.3 企业办公 3.4 在线教学与知识分享 四、总结 今天给大家推荐一款非常实用的电脑录屏软件&#xf…