今天写了一道十分有感觉的字符串处理题目。
题目简介
原题:UVa 112 Tree Summing
题目给出了一个十分具有Lisp风格的字符串,来表示一个二叉树,就像这样:
1
| (5(4(11(7()())(2()()))()) (8(13()())(4()(1()()))))
|
所要完成的任务是:判断每条从根部到叶子的路径上数的和是否等于一个给定的常数,如果是,则输出“yes”,否则输出“no”。
虽然是二叉树的题目,但是并不需要建立二叉树。只需调用递归函数,由系统来创建基于函数的二叉树。
所以我才说这题是字符串处理嘛~~~~
题目分析
这题有几个坑的点。
空树,就像这样
这种东西按照题目要求是要输出”no”的。在有些代码里面不需要特殊判断。
负数
1
| 5 (18 ( - 13 ( ) ( ))())
|
如果像我一样自己处理读入的数,就一定要注意负数的问题。这题负数就坑到我一回。在以上的测试样例中应该返回”yes”
叶子结点指的是左子树和右子树都为空的结点。
在我的第一个版本的代码里面,就是在左子树或右子树有一个为空时就输出了当前的和。
1
| 20 (5 () (5 () (5 () (5 () (4 () () ) ) ) ) )
|
刚好就撞到了上面这组测试数据的枪口上。。。
我的实现
不得不说我还是对C语言十分的喜爱啊。。
虽然打开编译器创建了一个test26.cpp
的文档,想写个C++来做这件事情。但是写完之后才发现,我还是只用了#include <stdio.h>
一个头文件。
1. 宏Getchar(x)
计算机读取数据是个十分矛盾的过程,比如我想要读取一个数字,读到左括号那里结束。但是如果我不读取出那个左括号,我就不知道我数字已经读取结束了。如果读出了那个左括号,我又相当于多读了一个东西。
所以我用了一个变量buffer
存储这个多读出来的值,用另一个变量bufflag
标志有没有使用这个buffer
。
在此基础上我重写了getchar
,如果buffer
正在使用,则返回buffer
中的值,否则返回输入流的下一个字符。
代码如下:
1 2 3 4 5 6
| if(bufflag) { bufflag = 0; x = buffer; } else { x = getchar(); }
|
2. 宏jumpSpace(x)
题目要求是这个字符串中间可以有任意的空白字符。于是我写了这个宏用来跳过中间所有的空白字符。
这个宏会循环调用宏Getchar(x)
,直到它找到一个不是空白字符的字符,并把结果返回给x。
代码如下:
1 2 3
| do { Getchar(x); } while (x == ' ' x == '\n' x == '\t' );
|
3. 宏ispnum(ch)
这个宏只被调用了一次。它用来判断读到的内容是不是一个数字。
注意,由于存在负数,所以如果读到-,也将被视为读到了一个数字,它代表即将读到的数是个负数。
实际上此时ch可能的值只有数字、-和)。其他的值都是不正确的。
代码如下:
1
| ch=='-'?1:(ch>='0'&&ch<='9'?1:0)
|
4. 宏nextNum(ch)
这个宏用来整理接下来即将从输出流中读出的一个整数。
如果ch为一个数字,接下来就会调用这个宏来找出以这个数字开头的完整的整数。这个宏将一直读到遇到第一个不是数字的地方停止。
但是此时它已经从输入流里读出了多余的东西。所以在这个宏的末尾,需要把这个多读出来的东西写入buffer。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| if(ch == '-') { scanf("%d", &ch); ch = -ch; } else { ch -= '0'; Getchar(k); while(k >= '0' && k <= '9') { ch = ch * 10 + ( k - '0' ); Getchar(k); } buffer = k; bufflag = 1; }
|
完整AC代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include <stdio.h> #define Getchar(x) if(bufflag){bufflag=0;x=buffer;}else x=getchar() #define jumpSpace(x) do{Getchar(x);}while(x==' 'x=='\n'x=='\t') #define ispnum(ch) ch=='-'?1:(ch>='0'&&ch<='9'?1:0) #define nextNum(ch) if(ch=='-'){scanf("%d",&ch);ch=-ch;}else{ch-='0';\ Getchar(k);while(k>='0'&&k<='9'){ch=ch*10+(k-'0');Getchar(k);}\ buffer=k;bufflag=1;} int caseNum; int flag; int buffer; int bufflag=0; int Insert(int sum){ int ch; int num; int k; jumpSpace(ch); jumpSpace(ch); if(ispnum(ch)){ nextNum(ch); num=sum+ch; if(Insert(num)&Insert(num)) if(num==caseNum) flag=1; }else return 1; jumpSpace(ch); return 0; } int main(int agrc, char *agrv[]) { while(scanf("%d",&caseNum)!=EOF) { flag=0; Insert(0); flag?printf("yes\n"):printf("no\n"); } return 0; }
|