题目描述
假设一个表达式有英文字母(小写)、运算符(+、-、*、/)和左右小(圆)括号构成,以 @ 作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则输出 YES;否则输出 NO。表达式长度小于 255,左圆括号少于 20 个。
输入格式
一行:表达式。
输出格式
一行:YES 或 NO。
cs
输入
2*(x+y)/(1-x)@
输出
YES
输入
(25+x)*(a*(a+b+b)@
输出
NO
说明/提示
表达式长度小于 255,左圆括号少于 20 个。
cs
#include<stdio.h>
#include<string.h>
int main()
{
char ch;
int balance = 0; // 括号平衡计数器,记录当前未匹配的左括号数量
//while循环判断在前面是否右括号多于左括号。在前面左括号可以多于右括号,因为后面可以补右括号。
//最后可以通过计数器是否为0来判断后面是否补上了。而如果在前面右括号多,就补不回来了。
while ((ch = getchar()) != '@') {
if (ch == '(') {
balance++; // 遇到左括号,计数器加1
} else if (ch == ')') {
balance--; // 遇到右括号,计数器减1
if (balance < 0) {
// 右括号出现在对应的左括号之前,不匹配
printf("NO\n");
return 0;
}
}
}
// 最后检查计数器是否为0
if (balance == 0) {
printf("YES\n");
} else {
printf("NO\n");
}
return 0;
}
我写代码主要有一个误区:我想的是一个在前面左括号必须要有一个右括号对应,完全忘记考虑可以在一个括号里套另一个括号,所以就导致我一直在考虑如何保证在第二个左括号前面有一个右括号,实际上,这是我无法写代码的,就一直进行不下去。
还有另一种方法,用栈数组:
cs
#include<stdio.h>
#include<string.h>
int main()
{
char input[255];
char ch;
int i = 0;//数组索引计数器
// 读取输入直到遇到 @
while ((ch = getchar()) != '@') {//这是用于字符串结束的固定方法,一定要记住
input[i++] = ch;//先用后加,所以应该是input[0]=ch;i++;
}
input[i] = '\0'; // 在数组末尾添加字符串结束符
int stack[255]; // 用数组模拟栈,存储左括号的位置
int top = -1; // 栈顶指针,-1表示空栈
int valid = 1; // 有效性标志,1表示有效,0表示无效
for (i = 0; i < strlen(input); i++) {
if (input[i] == '(') {
// 遇到左括号,入栈
stack[++top] = i;//先加后用,所以下标是从0开始的
} else if (input[i] == ')') {
// 遇到右括号
//这其实和上面的代码一样的思路,都是通过一个标志变量的值看是否括号匹配
if (top == -1) {//说明右括号在前面出现了两次,一个左括号对应两个右括号
// 栈为空,说明右括号没有对应的左括号
valid = 0;//标志变量用于输出后面的结果
break;
} else {
// 弹出栈顶的左括号
top--;
}
}
}
// 检查:所有括号都应该匹配,栈应该为空
if (valid == 1 && top == -1) {
printf("YES\n");
} else {
printf("NO\n");
}
return 0;
}
cs
示例1:a(b)c
索引 | 字符 | 操作 | stack | top | valid
-----|------|----------------|--------|-----|-------
0 | 'a' | 忽略 | [] | -1 | 1
1 | '(' | 入栈 stack[0]=1| [1] | 0 | 1
2 | 'b' | 忽略 | [1] | 0 | 1
3 | ')' | 出栈 top-- | [1] | -1 | 1
4 | 'c' | 忽略 | [1] | -1 | 1
结束:top = -1, valid = 1
示例2:a(b@
索引 | 字符 | 操作 | stack | top | valid
-----|------|----------------|--------|-----|-------
0 | 'a' | 忽略 | [] | -1 | 1
1 | '(' | 入栈 stack[0]=1| [1] | 0 | 1
2 | 'b' | 忽略 | [1] | 0 | 1
结束:top = 0, valid = 1
示例3:a)b(c@
索引 | 字符 | 操作 | stack | top | valid
-----|------|----------------|--------|-----|-------
0 | 'a' | 忽略 | [] | -1 | 1
1 | ')' | top==-1 → valid=0| [] | -1 | 0
立即退出循环
判断逻辑:
-
valid == 1:在处理过程中没有发现不匹配的情况 -
top == -1:所有左括号都被匹配了(栈为空)
四种可能情况:
-
✅
valid=1, top=-1→ YES(完全匹配) -
❌
valid=1, top≠-1→ NO(左括号多余) -
❌
valid=0, top=-1→ NO(右括号多余) -
❌
valid=0, top≠-1→ NO(多种错误)
为什么要在输入所有字符后要在后面添加字符串结束符呢?
是因为计算字符串长度的时候,遇到字符串结束符才会停止。如果没有字符串结束符就会一直读取后面的随机值,长度会不停的增加,长度测量不精准。
需要明确的是:
char str[] = "Hello"; // 实际存储:['H','e','l','l','o','\0']
| 概念 | 含义 | 示例值 | 包含 \0 吗? |
|---|---|---|---|
| 数组大小 | 分配的内存空间 | 6个字节 | ✅ 包含 \0 |
| 字符串长度 | 有效字符个数 | 5个字符 | ❌ 不包含 \0 |