7-22 符号配对(PTA)

7-22 符号配对

题目背景

请编写程序检查C语言源程序中下列符号是否配对:/**/()[]{}

输入格式:

输入为一个C语言源程序。当读到某一行中只有一个句点.和一个回车的时候,标志着输入结束。程序中需要检查配对的符号不超过100个。

输出格式:

首先,如果所有符号配对正确,则在第一行中输出YES,否则输出NO。然后在第二行中指出第一个不配对的符号:如果缺少左符号,则输出?-右符号;如果缺少右符号,则输出左符号-?

输入样例1:

void test()
{
    int i, A[10];
    for (i=0; i<10; i++) { /*/
        A[i] = i;
}
.

输出样例1:

NO
/*-?

输入样例2:

void test()
{
    int i, A[10];
    for (i=0; i<10; i++) /**/
        A[i] = i;
}]
.

输出样例2:

NO
?-]

输入样例3:

void test()
{
    int i
    double A[10];
    for (i=0; i<10; i++) /**/
        A[i] = 0.1*i;
}
.

输出样例3:

YES

鸣谢用户 王渊博 补充数据!

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

栈限制

8192 KB

题目分析

本题其实是一个经典的使用堆栈结构解决符号匹配问题。

首先需要明确什么样的符号组合是不合法的

缺少左符号的定义:

例如:}或{}}等情况。前面的符号全部得到匹配,但是出现了没有左边符号的右符号。

缺少右符号的定义:

例如:{或{【】等情况。出现一直未能匹配的左符号。

所谓的第一个不匹配的符号:

例如:出现情况{】,左右符号不能匹配,此时应该提示出现的较早的{的问题,即缺少右符号。

特别的,出现情况{【},应当判定为“符号【缺少右符号”,出现情况{】}却应该判定为“符号{缺少右符号”。

据此,本题有如下难点或易错点:

  1. 堆栈空:容易访问空的栈。每次取出栈顶元素时,应当首先判断栈是否为空!在不同时候堆栈空可能对应不同的问题。
  2. 符号长度不同:对于括号和注释,占用的长度不同,需要特别注意。
  3. 循环结束后的判断:循环检查结束后,不要忘记检查栈,若栈内还有元素,应当是错误的程序,应该给出NO的判断。

代码思路

栈的定义

由于符号长短不一,将栈定义为string类型,可以储存不同长度的左符号。

获取输入

由于要求一排一排查看是否退出,所以需要使用getline来读取。然后在每排查看符号是否是左右符号,对符合左右符号的位置进行检测。

检测思路

遇到左符号,无需顾虑太多,直接入栈即可。注意,符号“/*”的检测可以使用:data[i] == '/' && i + 1 < data.length() && data[i+1] == '*'即可。该符号检测完,应该让i额外加一,以跳过第二个字符。

遇到右符号,首先看栈是否为空。如果为空,显然此时是缺少左符号,按照当前右符号输出对应提示即可。

如果栈不为空,那么取出栈顶元素。栈顶元素如果与当前右符号匹配,则弹栈即可。

如果不匹配,那么此时是例如{】的情况,按上文所述,判断为缺少右符号,提示栈顶元素缺少右符号即可。

另外,右符号“*/”识别思路与上文“/*”相似,同样应该注意检测完,应该让i额外加一,以跳过第二个字符。

最后整个程序结束后,判断栈是否空。若为空且前面未检测出异常,则整个程序无误。若不为空,那么显然犯了缺少右符号的问题。此时提示栈顶元素缺少有符号即可。

代码

#include <iostream>
#include <stack>
#include <string>
using namespace std;

int main() {
	stack<string> fh;
	string data;
	int OK = 0;
	while (OK >= 0) {
		getline(cin, data);
		if (data == ".") {
			break;
		}
		for (int i = 0; i < data.length(); i++) {
			if (data[i] == '(') {
				fh.push("(");
			}
			if (data[i] == '[') {
				fh.push("[");
			}
			if (data[i] == '{') {
				fh.push("{");
			}
			if (data[i] == '/' && i + 1 < data.length()) {
				if (data[i + 1] == '*') {
					fh.push("/*");
					if (i + 2 < data.length()) {
						i++;
						continue;
					} else {
						break;
					}
				}
			}
			if (data[i] == ')') {
				if (fh.empty()) {
					cout << "NO" << endl;
					cout << "?-)";
					OK = -1;
					break;
				} else if (fh.top() != "(") {
					cout << "NO" << endl;
					cout << fh.top() << "-?";
					OK = -1;
					break;
				} else {
					fh.pop();
				}
			}
			if (data[i] == ']') {
				if (fh.empty()) {
					cout << "NO" << endl;
					cout << "?-]";
					OK = -1;
					break;
				} else if (fh.top() != "[") {
					cout << "NO" << endl;
					cout << fh.top() << "-?";
					OK = -1;
					break;
				} else {
					fh.pop();
				}
			}
			if (data[i] == '}') {
				if (fh.empty()) {
					cout << "NO" << endl;
					cout << "?-}";
					OK = -1;
					break;
				} else if (fh.top() != "{") {
					cout << "NO" << endl;
					cout << fh.top() << "-?";
					OK = -1;
					break;
				} else {
					fh.pop();
				}
			}
			if (data[i] == '*') {
				if (i + 1 < data.length()) {
					if (data[i + 1] == '/') {
						if (fh.empty()) {
							cout << "NO" << endl;
							cout << "?-*/";
							OK = -1;
							break;
						} else if (fh.top() != "/*") {
							cout << "NO" << endl;
							cout << fh.top() << "-?";
							OK = -1;
							break;
						} else {
							fh.pop();
							if (i + 2 < data.length()) {
								i++;
								continue;
							} else {
								break;
							}
						}
					}
				}
			}
		}
	}
	if (OK == 0) {
		if (fh.empty()) {
			cout << "YES";
		} else {
			cout << "NO" << endl;
			cout << fh.top() << "-?";
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值