每日一题---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{
        //当栈为空,且遇到右括号,栈里面没有左括号,返回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题---有效的括号,里面包含了栈的一些基础知识,希望看完这篇文章能对友友们有所帮助 !  !  !

点赞收藏加关注 !   !   !

谢谢大家 !   !   !

  • 29
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值