天梯赛习题:7-8 符号配对(栈的运用 + 合理处理)

24 篇文章 0 订阅
6 篇文章 0 订阅
7-8 符号配对 (20 分)
请编写程序检查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

【思路】
这道题考试的时候也是死磕了一下,毕竟分值很大,不想丢掉,但磕到最后,也只是悲惨的水到了4分左右的样子,不仅如此,还耗费了大量时间。这次要引以为戒,天梯赛上遇到难磕的题千万不能陷死在里面了。。。

其实这题并不难,基本思路就是利用栈,如果字符和栈顶的字符匹配,那么我就把栈顶元素弹出来。如果不匹配,我就压进去。我当时只想到这一步,然后就开始信心满满的做,做到最后提交答案错误和段错误。。。然后就没法继续了。。

题目不难,但这题AC率是最低的,当时考试的时候只有0.06.。。我觉得,这道题真正难的地方不是思路,而是合理设计代码,然后处理大量的细节,这个真的很繁琐

我参考了这位博主的代码,他的代码设计的很好:https://blog.csdn.net/qq_41611106/article/details/82590671

总结一下我为什么实现出来就乱七八糟,他实现出来就显得非常有条理:
1.我用的string,他用的char数组。其实这两个都无所谓,但是他用起来还是比我的string看着爽一些,这就是基本功的差距了。char数组可以将字符串末尾的\0读进来,用scanf("%s", str);不能读空格,他相当于没有管空格,因为空格在这里确实也不用管。而我用的是getline(cin, str),把空格也一口气的读进来了
2.他采用了的输出思路是,一旦找到一个不匹配的,就直接输出了,flag变为true。
而我的思路不是边读边输出,而是最后在总的输出。其实,这一点,我觉得他的设计就比我更好了,这样不至于在最后考虑太多种情况,而且提高了速度,只要找到一个不匹配,后面的就不用再找了。
3.对于注释符号/*我已开始是不知道怎么处理的,因为它由两个符号组成。但是他设计的就挺好,如果找到注释符号,那么就往栈中压入一个<,这样用一个符号就代替了两个符号了!
4.栈pop的首要条件是栈不为空,这点我没有考虑,于是最后也是出现大量段错误!
5.逻辑的问题我出现了错误。比如栈顶现在是[,然后来了一个},那么这个时候第一个不匹配的元素其实是栈顶的[,而不是}。我一开始以为是},这一点就想错了。
6、最后,其实如果遇到了( [ {这种左括号的字符,我们直接压到栈中去就行了,匹配的是右括号。最后如果栈中还有字符,那么肯定是这种左括号字符,输出栈顶的那一个就可以了。这样思考问题就简单多了。

所以,我跟他的很多思考问题的方式还是很有差距的。这其实并不是算法了,感觉是一种处理问题的能力,这种能力要大量刷题训练才行,要让我们每次思考问题都能想到一种最简化的处理问题方式。

所以有时候,真不是算法题目太难,而是你思考的方向南辕北辙,你设计的数据结构不合理。

代码:

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

int main()
{
	char str[102];
	stack<char> s;
	bool flag = false;
	while(true)
	{
		scanf("%s", str);
		if(str[0] == '.' && str[1] == '\0')	break;		//我们每次会读入一个\0字符进来
		//开始遍历str字符数组 
		for(int i = 0;str[i] != '\0';i++)
		{
			if(flag)	break;		//如果找到一个,后面的字符串还得读取,但不需要判断了 
			if(str[i]=='(' || str[i] =='[' || str[i]=='{'){
				s.push(str[i]);
			}
			//这样来判断注释符号! 
			else if(str[i] == '/' && str[i + 1] == '*'){
				s.push('<');	//非常巧妙!用一个<代替注释符号! 
				i++;			//后面那个字符就不用再看了 
			}
			else if(str[i] == ')'){
				//栈不为空是一个前提!否则一定段错误! 
				if(!s.empty() && s.top() == '(')	s.pop();	
				else{
					cout << "NO" << endl;
					flag = true;			//已经找到一个不匹配的了 
					//cout << "?-)" << endl;
					//这里的逻辑问题注意一下
					if(s.empty()){
						cout << "?-)" << endl;
					} 
					else//说明栈顶元素和)不匹配,那么第一个不配对的实际上是栈顶元素 
					{
						if(s.top() == '<')
							cout << "/*-?" << endl;
						else
							cout << s.top() << "-?" << endl;
					}
					break;
				} 
			}
			 else if(str[i] == ']') {  
                if(!s.empty() && s.top() == '[') s.pop();  
                else {  
                    printf("NO\n");  
                    flag = true;  
                    if(s.empty()) {  
                        printf("?-]\n");  
                    }  
                    else {  
                    	if(s.top() == '<')
                    		cout << "/*-?" << endl;
                    	else
                        	cout << s.top() << "-?" << endl; 
                    }  
                    break;  
                }  
            }  
            else if(str[i] == '}') {  
                if(!s.empty() && s.top() == '{') s.pop();  
                else {  
                    printf("NO\n");  
                    flag = true;  
                    if(s.empty()) {  
                        printf("?-}\n");  
                    }  
                    else {  
                    	if(s.top() == '<')
                    		cout << "/*-?" << endl;
                    	else
                        	cout << s.top() << "-?" << endl; 
                    }  
                    break;  
                }  
            }
            //如果是反注释符号 
			else if(str[i] == '*' && str[i + 1] == '/')
			{
				i++;	
				if(!s.empty() && s.top() == '<'){	
					s.pop();
				}
				else{
					cout << "NO" << endl;		
					if(s.empty()){ 
						cout << "?-*/" << endl;
					}
					else{		//栈顶元素不匹配 
						cout << s.top() << "-?" << endl;
					}
					flag = true;
					break;		//找到一个不匹配的字符,直接跳出即可 
				}
			}  
		} 
	}
	//注:此时还有一种情况,就是栈中都是左边字符,比如(,[,{,这样的话flag还是false 
	if(!flag && s.empty()) 		//如果栈是空的,才证明完全匹配了 
		cout << "YES" << endl;
	else if(!flag){				//否则,里面肯定还有一系列的左边字符 
		cout << "NO" << endl;	//这句话差点写掉了 
		if(s.top() == '<')		//这句特判不要掉! 
			cout << "/*-?" << endl;
		else
			cout << s.top() << "-?" << endl;
	}
	return 0;
}
  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值