数据结构题解——有效括号(以及栈的实现)

题目描述(链接:https://leetcode.cn/problems/valid-parentheses/

样例

大意就是判断字符串内的括号是否两两匹配(注意,并不只有() [] {}此类样式还包含但不限 ({[()]}) ({}{}[]) 等 ),既然通过栈来实现,那必然会考虑入栈问题,怎么入呢?那些入那些不入呢?

最起初我没有考虑完全,就直接让字符串内所有元素全部入栈,然后在取栈顶元素再出栈再取栈顶元素来进行对比,如图:

若是如图所示的有效括号类型的话,第二次出栈的就会与第一次出栈的相匹配,但是很明显,当左括号和右括号对称顺序时(如:({[()]}) )该方法就不适用了。(这种全部入栈与只如一个直接匹配的方法都是不可取的,错误点都差不多就不提了)。

经观察不难发现,当字符串为有效括号时,字符串长度始终为偶数,因此可以先通过判断奇偶来排除一部分;另一方面,有效括号始终是左括号在最前,接着不是相应的右括号就是接着左括号。因此,我们就可以拿栈来接收左括号,当读到右括号时就与栈顶元素作比较,匹配就出栈并查看下一个括号,这么一来问题就解决了。

上代码之前,由于是栈来解决该题,那么建栈就是必须的一步,最简单实现方式就是数组实现(虽然数组可以通过下标访问其内部对应元素,但是在这里我们构造的是栈,因此要避免直接访问内部的数据,不然就违背了栈的“先进后出”原则),那么这是关于建栈的相关代码:

//自定义类型以及声明

typedef char STDataType;

typedef struct Stack 
{
    STDataType* a;//动态扩容能有效避免因栈大小不够而出现的问题
    int top;
    int capacity;
}ST;

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

void STDestroy(ST* ps);//栈销毁

void STPush(ST* ps, STDataType x);//入栈

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

int STSize(ST* ps);//栈大小

bool STEmpty(ST* ps);//栈是否存在以及为空

STDataType STTop(ST* ps);//栈顶元素
bool STEmpty(ST* ps)//判空
{
    assert(ps);
    return ps->top == 0;
}

void STInit(ST* ps)//初始化
{
    assert(ps);
    STDataType* a = (STDataType*)malloc(sizeof(STDataType) * 4);
    if (a == NULL)
    {
        perror("malloc fail");
        return;
    }
    ps->a = a;
    ps->capacity = 4;
    //top初始化为0,入栈时直接以top为下标插入再++就好了
    //但是在出栈或查看栈顶元素时要对下标为top-1的元素进行操作
    ps->top = 0;
}

void STPush(ST* ps, STDataType x)//入栈
{
    assert(ps);
    if (ps->top == ps->capacity)
    {
        STDataType* a = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);
        if (a == NULL)
        {
            perror("malloc fail");
            return;
        }
        ps->a = a;
        ps->capacity = ps->capacity * 2;
    }
    ps->a[ps->top] = x;
    ps->top++;
}

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

int STSize(ST* ps)//查看栈大小
{
    assert(ps);
    return ps->top;
}

STDataType STTop(ST* ps)//查看栈顶元素
{
    assert(ps);
    return ps->a[ps->top-1];
}

void STDestroy(ST* ps)//栈销毁
{
    assert(ps);
    free(ps->a);
    ps->a = NULL;
    ps->top = 0;
}

当然,在实际做题时并不会用到上述所有功能,提取需要的代码即可,接着就是本题的代码了

bool isValid(char * s)
{
    if(s==NULL)
    {
        return false;
    }
    ST stack;
    STInit(&stack);
    while(*s)
    {
        //只对左括号进行入栈
        if(*s=='[' || *s=='{' || *s=='(')
        {
            STPush(&stack,*s);
        }
        else
        {
            if(STEmpty(&stack))
            {
                STDestroy(&stack);
                return false;
            }
            char top = STTop(&stack);
            STPop(&stack);
            //比起判断成立不进行任何操作,判断不成立直接终止来得快得多
            if(top=='('&&*s!=')' ||
               top=='['&&*s!=']' ||
               top=='{'&&*s!='}')
                {
                    STDestroy(&stack);
                    return false;
                }
        }
        s++;
    }
    //观察判断代码可以发现,当字符串全为左括号时,依然能到达这个位置,因此进行一次判空
    if(!STEmpty(&stack))
    {
        STDestroy(&stack);
        return false;
    }
    //空间的释放很重要,虽然不会报错,但是养成好的习惯可以以备不时之需
    STDestroy(&stack);
    return true;
}

感谢阅读,希望能对你有所帮助。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值