栈 典型OJ题目--- 括号匹配问题

文章介绍了如何使用栈来判断字符串中的括号是否匹配,通过遍历字符串,遇到左括号入栈,遇到右括号则与栈顶的左括号匹配。在代码实现中,遇到了两个问题:一是只有左括号的情况,通过检查栈是否为空来修正;二是只有右括号的情况,添加了栈为空时直接返回false的判断。最后强调了代码的严谨性,包括栈的销毁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

 题意解读

 说白了这道题就是 内部会输入一个字符串,字符串里面有若干字符,每个字符只可能是(  {  [  )  } ]

这六个括号中的一个,你需要做的是 写一段代码来判断给定的字符串中的这些括号是否匹配,什么叫括号是否匹配?

首先有左括号就得有对应的右括号,必如说 " ( [ " 这就不是有效的括号

再者左括号和对应的右括号位置要对应,比如说: " ( [  )  ]  " 这就不是有效的括号

思路

遍历字符串的每个字符

如果是左括号就入栈,如果是右括号就让左括号出栈和右括号进行匹配,看是否匹配

 代码实现

 按照上述思路:我们先初步实现一下

下面要用到栈,因此我们把前面博客写过的栈的实现代码直接搬过来

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>

typedef char STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;  
	int capacity; 
}ST;

//栈初始化
void STInit(ST* pst);

//栈的销毁
void STDestroy(ST* pst);

//压栈
void STPush(ST* pst,STDataType x);

//出栈
void STPop(ST* pst);

//获取栈顶元素
STDataType STTop(ST* pst);

//判空
bool STEmpty(ST* pst);

//获取size
int STSize(ST* pst);

//栈的初始化
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;

	//pst->top = -1; //top指向栈顶元素
	pst->top = 0; //top指向栈顶元素的下一个位置
	pst->capacity = 0;
}


//栈的销毁
void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->a);
	pst->a = NULL;
	pst->top = pst->capacity = 0;
}


//压栈
void STPush(ST* pst, STDataType x)
{
	if (pst->top == pst->capacity)
	{
		int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = realloc(pst->a, newCapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail\n");
			return;
		}
		pst->a = tmp;
		pst->capacity = newCapacity;
	}

	pst->a[pst->top] = x;
	pst->top++;
}


//出栈
void STPop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	pst->top--;
}


//获取栈顶元素
STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top - 1];
}


//判空
bool STEmpty(ST* pst)
{
	return pst->top == 0;
	//或者写成
	// return !(pst->top)
}


//获取栈的元素个数
int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}

下面是这道题的主体代码

bool isValid(char * s){
    ST st;
    STInit(&st);
    while(*s)
    {
        if(*s == '(' || *s == '[' || *s == '{')
        {
            STPush(&st, *s);
        }
        else
        {
            char top = STTop(&st);
            STPop(&st);
            if(*s == ']' && top!='[' 
              || *s == '}' && top != '{'
              || *s == ')' && top != '(')
              {
                  return false;
              }
        }
        s++;
    }
    return True;
}

下面详细解释一下这段代码的要点:

②s是题目中已经给定的函数形参,是一个字符串,字符串是以'\0'为结束标志的,因此while(*s)就作为while循环体继续执行的条件

③If else 用来判断是左括号还是右括号,左括号就入栈,右括号就与出栈的左括号进行比较

④这部分是关键,意思就是只要有一对括号没匹配上,那么就直接返回false

遇到的问题

 问题一

就这样直接运行代码,发现并没有通过测试,分析题目所给未通过示例,可以发现,当给定字符串只有左括号时,会出现问题

因为只有左括号的时候,else分支压根没有进去,当遍历完字符串时,直接来到最后一句return true了,因此出现了问题

怎么改正呢?我们不妨思考一下,当题中所给字符串是有效的括号时,按照我们的方法,栈最后一定是空的,因此我们可以在最后加上这么一段代码:

 判断一下栈是否为空,如果为空,则返回True,不为空,返回False,符合我们分析的结果

问题二

但是直接提交仍然有问题

 可以看到当字符串只有右括号的时候,直接进入else语句中的STTop代码,但是由于没有左括号入栈,因此栈为空,STTop中的assert断言就会报错

改进:只需要在else语句中加入if条件判断,如果为空,直接返回false即可

 

 更严谨的写法~

不过我们学编程还是要更加严谨一点~,该题中的栈ST是我们自己创建的,那么最后当然应该销毁了,虽然Leetcode并没有进行这方面严格检查,但是养成好习惯还是很重要的~

 完整代码

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>

typedef char STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;  
	int capacity; 
}ST;

//栈初始化
void STInit(ST* pst);

//栈的销毁
void STDestroy(ST* pst);

//压栈
void STPush(ST* pst,STDataType x);

//出栈
void STPop(ST* pst);

//获取栈顶元素
STDataType STTop(ST* pst);

//判空
bool STEmpty(ST* pst);

//获取size
int STSize(ST* pst);

//栈的初始化
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;

	//pst->top = -1; //top指向栈顶元素
	pst->top = 0; //top指向栈顶元素的下一个位置
	pst->capacity = 0;
}


//栈的销毁
void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->a);
	pst->a = NULL;
	pst->top = pst->capacity = 0;
}


//压栈
void STPush(ST* pst, STDataType x)
{
	if (pst->top == pst->capacity)
	{
		int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = realloc(pst->a, newCapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail\n");
			return;
		}
		pst->a = tmp;
		pst->capacity = newCapacity;
	}

	pst->a[pst->top] = x;
	pst->top++;
}


//出栈
void STPop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	pst->top--;
}


//获取栈顶元素
STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top - 1];
}


//判空
bool STEmpty(ST* pst)
{
	return pst->top == 0;
	//或者写成
	// return !(pst->top)
}



int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}


bool isValid(char * s){
    ST st;
    STInit(&st);
    while(*s)
    {
        if(*s == '(' || *s == '[' || *s == '{')
        {
            STPush(&st, *s);
        }
        else
        {
            if(STEmpty(&st))
            {
                STDestroy(&st);
                return false;
            }
            char top = STTop(&st);
            STPop(&st);
            if(*s == ']' && top!='[' 
              || *s == '}' && top != '{'
              || *s == ')' && top != '(')
              {
                  STDestroy(&st);
                  return false;
              }
        }
        s++;
    }
    bool ret = STEmpty(&st);
    STDestroy(&st);
    return ret;
}

本篇有效的括号这道题就分享到这啦,欢迎大家交流指正~

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值