题目描述(链接:https://leetcode.cn/problems/valid-parentheses/)
![](https://i-blog.csdnimg.cn/blog_migrate/67740551ddca3fc7af3baee08fa5ee58.png)
样例
![](https://i-blog.csdnimg.cn/blog_migrate/f9b58b14207da1bb931ac93258c72ba5.png)
大意就是判断字符串内的括号是否两两匹配(注意,并不只有() [] {}此类样式还包含但不限 ({[()]}) ({}{}[]) 等 ),既然通过栈来实现,那必然会考虑入栈问题,怎么入呢?那些入那些不入呢?
最起初我没有考虑完全,就直接让字符串内所有元素全部入栈,然后在取栈顶元素再出栈再取栈顶元素来进行对比,如图:
![](https://i-blog.csdnimg.cn/blog_migrate/8d3f4b077bdfaae10fa0009e5f0a1260.png)
若是如图所示的有效括号类型的话,第二次出栈的就会与第一次出栈的相匹配,但是很明显,当左括号和右括号对称顺序时(如:({[()]}) )该方法就不适用了。(这种全部入栈与只如一个直接匹配的方法都是不可取的,错误点都差不多就不提了)。
经观察不难发现,当字符串为有效括号时,字符串长度始终为偶数,因此可以先通过判断奇偶来排除一部分;另一方面,有效括号始终是左括号在最前,接着不是相应的右括号就是接着左括号。因此,我们就可以拿栈来接收左括号,当读到右括号时就与栈顶元素作比较,匹配就出栈并查看下一个括号,这么一来问题就解决了。
上代码之前,由于是栈来解决该题,那么建栈就是必须的一步,最简单实现方式就是数组实现(虽然数组可以通过下标访问其内部对应元素,但是在这里我们构造的是栈,因此要避免直接访问内部的数据,不然就违背了栈的“先进后出”原则),那么这是关于建栈的相关代码:
//自定义类型以及声明
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;
}
感谢阅读,希望能对你有所帮助。