B2165 括号匹配 题解

给定只由 6 种括号字符组成的字符串:(, ), [, ], {, }。判断每个字符串是否为“合法括号序列”,合法则输出 YES,否则输出 NO。

输入 #2

6
()
([)]
([]){}
((((
{[()()]}
}{

输出 #2

YES
NO
YES
NO
YES
NO

题解

对于一个右括号,它如果能够被匹配,那么只能与它左边最近的尚未匹配的左括号匹配。

因此我们只需要维护这些尚未匹配的左括号,并且每次只关心最后加入的一个。

我们可以用如下的方式维护:

char stk[10000]; 
int top = 0;
​
stk[top] = c; top++; // 加入一个尚未匹配的左括号
top--; // 匹配一个括号

这种结构被称为栈。stk[top-1] 所对应的字符即为最后一个未匹配的左括号。

对于当前字符:

  • 如果是 (、[、{,直接压入栈中;

  • 如果是 )、]、}:

    • 如果栈为空,说明这个右括号找不到对应的左括号,序列非法;

    • 否则检查栈顶:

      • ) 必须对应 (;

      • ] 必须对应 [;

      • } 必须对应 {。

    • 如果类型不同,则序列非法;

    • 如果类型相同,则弹出栈顶。

扫描结束后,还需要检查栈是否为空。

如果栈不为空,说明还有左括号没有被匹配,例如:

(([]

因此只有在扫描过程中没有发生失配,并且最终栈为空时,括号序列才合法。

参考代码如下

作者:刘向奥

#include <stdio.h>
#include <string.h>
​
char a[1000010];
char stk[1000010]; int top = 0;
​
void solve()
{
    top = 0;
    scanf("%s", &a);
    int len = strlen(a);
    for(int i = 0; i < len; i++)
    {
        char c = a[i];
        if (c == '(' || c == '[' || c == '{')
        {
            stk[top] = c; top++;
        }else // ) ] }
        {
            if(top == 0 
              || (c == ')' && stk[top-1] != '(')
              || (c == ']' && stk[top-1] != '[')
              || (c == '}' && stk[top-1] != '{') )
            {
                printf("NO\n");
                return;
            }
            top--;
        }
    }
    if(top != 0) printf("NO\n");
    else printf("YES\n");
}
​
int main()
{
    int t; scanf("%d", &t);
    for(int i = 0; i < t; i++)
    {
        solve();
    }
}