1 条题解

  • 0
    @ 2025-4-9 22:56:06

    题意分析

    本题聚焦于对D++程序文本的语法规则检查,核心规则涉及括号与注释。

    D++程序文本由三部分构成:注释、算术表达式以及符号部分。注释能在文本各处出现,以“(”开启,“)”结束,且必须成对出现,比如“(这是一条注释)”。算术表达式以“(”起始、“)”终结,可含“=+-*/0123456789)("及注释,但不允许有空格(换行符除外),其括号需平衡,像“((1))”这类括号不平衡的就不正确。符号部分指去除注释和算术表达式后的文本,不能有“(”和“)”。

    需要特别注意,除算术表达式内部,其他位置可出现空格。

    输入方面,标准输入给出一段不超10000个符号的文本,内容涵盖拉丁字母、数字、括号、算术运算符号、换行符和回车符。输出则依据输入文本是否为正确的D++程序,若是输出“YES”,否则输出“NO”。如给定输入

    Hello, here is a sample D++ program. It contains some arithmetical expressions like
    (2+2=4), (2+-/*) and ((3+3)*3=20(this is not true, but you don't have to verify it :-) )+8)
    ( the closing bracket in the previous comment is also in order, since this bracket
    does not belong to any arithmetical expression)
    
    因符合所有规则,输出“YES” 。

    解题思路

    1.利用map来记录合法字符,方便后续快速判断字符是否合法。

    2.通过一个变量sum来记录当前括号的匹配状态,遇到左括号(sum加1,遇到右括号)sum减1 。

    3.用flag标记是否处于注释状态,当遇到(*时进入注释状态(flag = 1),遇到*)时退出注释状态(flag = 0) 。

    4.在处理过程中,根据不同的字符和状态进行相应的操作,最后根据sumflag和整体的合法性标记ans来判断输入的字符串是否为合法的D++程序。

    分析

    1.时间复杂度:对输入的每个字符都进行一次处理,假设输入字符串长度为nn,则时间复杂度为O(n)O(n)。因为每次字符处理的操作(如判断字符类型、更新状态变量等)基本都是常数时间操作。

    2.空间复杂度:使用了一个map来存储合法字符,map的大小是固定的(14个元素),还使用了一些辅助变量(如sumflagans等),这些辅助变量的空间复杂度为常数级。所以总的空间复杂度为O(1)O(1)

    实现步骤

    1.初始化数据结构和变量:初始化一个map<char, bool> vis,将所有合法字符标记为true;初始化变量sumflagans分别用于记录括号匹配状态、注释状态和整体合法性,初始值分别为001

    2.字符读取与处理:通过scanf("%c", &t)逐字符读取输入。

    3.当处于注释状态(flag == 1)或者整体已经判定为不合法(ans == 0)时,仅处理结束注释的)字符,其他字符跳过,更新last字符。

    4.当遇到(*时,进入注释状态(flag = 1),并将sum减1(这里减1操作可能是为了平衡后续对括号的计数逻辑)。

    5.当sum0且遇到)且前一个字符是*时,说明注释结束符号位置不对,将ans设为0表示不合法。

    6.根据sum的值进行不同处理:

    (1)当sum < 0时,说明括号匹配已经出错,将ans设为0并跳过后续处理。

    (2)当sum > 0时,遇到)sum减1,遇到(sum加1,遇到非法字符(vis[t] == 0)则将ans设为0,并更新last字符。

    (3)当sum == 0时,遇到(sum加1,遇到)sum减1,并更新last字符。

    7.结果输出:读取结束后,如果sum不为0(括号未匹配)或者flag1(注释未结束)或者ans0(过程中发现不合法情况),则输出NO;否则输出YES

    代码实现

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #include<stack>
    #include<cstdlib>
    #include<iomanip>
    #include<string>
    #include<vector>
    #include<map>
    #include<string>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define INF 0x3f3f3f3f
    typedef long long ll;
    #define Max(a,b) (a>b)?a:b
    #define lowbit(x) x&(-x)
    int main()
    {
    	map<char,bool>vis;
    	vis['1']=1;
    	vis['2']=1;
    	vis['3']=1;
    	vis['4']=1;
    	vis['5']=1;
    	vis['6']=1;
    	vis['7']=1;
    	vis['8']=1;
    	vis['9']=1;
    	vis['0']=1;
    	vis['+']=1;
    	vis['-']=1;
    	vis['*']=1;
    	vis['/']=1;
    	vis['\n']=1;
    	vis['=']=1;
    	char t,last=0;
    	int sum=0,flag=0,ans=1;
    	while(~scanf("%c",&t))
    	{
    		if(flag==1||ans==0)
    		{
    			if(t==')')
    			{
    				if(last=='*')
    				{
    					flag=0;
    				}
    			}
    			last=t;
    			continue;
    		}
    		if(t=='*'&&last=='(')
    		{
    			flag=1,sum--;
    			continue;
    		}
    		else if(sum==0&&t==')'&&last=='*')
    			ans=0;
    		if(sum<0)
    		{
    			ans=0;
    			continue;
    		}
    		else if(sum>0)
    		{
    			if(t==')')
    			{
    				sum--;
    			}
    			
    			else if(t=='(')
    				sum++;
    			else if(vis[t]==0)
    				ans=0;
    			last=t;
    		}
    		else
    		{
    			if(t=='(')
    			{
    				sum++;
    			}
    			else if(t==')')
    				sum--;
    			last=t;
    		}
    	}
    	if(sum||flag||ans==0)
    		puts("NO");
    	else
    		puts("YES");
    }
    

    代码说明

    1.头文件和命名空间

    包含了<cstdio>用于输入输出操作,<cmath>用于数学运算(虽然本题未使用),<cstring>用于字符串处理,<queue><stack>用于队列和栈相关操作(本题未使用),<cstdlib>用于标准库函数,<iomanip>用于输入输出格式控制(本题未使用),<string>用于字符串操作,<vector>用于向量操作(本题未使用),<map>用于映射数据结构,<iostream>用于输入输出流,<algorithm>用于算法相关操作(本题未使用)。

    使用using namespace std;使代码可以直接使用标准命名空间中的函数和类型。

    2.宏定义和类型定义

    #define INF 0x3f3f3f3f定义了一个很大的数,通常用于表示无穷大(本题未使用)。

    typedef long long ll;long long类型重命名为ll(本题未使用)。

    #define Max(a,b) (a>b)?a:b定义了一个宏,用于返回两个数中的较大值(本题未使用)。

    #define lowbit(x) x&(-x)定义了一个宏,用于获取一个数的二进制表示中最低位的1及其后面的0(本题未使用)。

    3。主函数部分

    初始化map<char, bool> vis,将所有合法字符标记为true,包括数字、算术运算符、\n=

    初始化字符变量last0,用于记录上一个字符;初始化sumflagans变量。

    通过while(~scanf("%c", &t))循环逐字符读取输入,在循环内部按照上述的实现步骤进行字符处理。

    循环结束后,根据sumflagans的值输出相应的结果,NO表示输入不是合法的D++程序,YES表示是合法的D++程序。

    • 1