2018普及组——对称二叉树

键盘炸了,算是用手机一字一字地写完了。。。
由于是用手机写的,如有错别字也请谅解。(这不是你语文不好的理由!)
看到大佬的代码满篇%号乱飞,果然不是我等蒟蒻能轻易看懂的,在此写下低端代码题解一篇。

正文

对称二叉树

在考试的时候想错了,花了一个多小时与指针纠缠(程序还一直RE),终于在交卷前十分钟发现了更便捷的方法(还过了样例),终于在考试结束前的最后一刻调了出来!(虽然最终在老师的lemon上MLE 0分,洛谷上TLE 84分QAQ。。。)

原思路

Step 1:输入。

scanf("%d",&n);							//输入节点数
for(int i=1;i<=n;++i)
	scanf("%d",&c[i]);					//输入每个结点的权值
for(int i=1;i<=n;++i)
	scanf("%d%d",&so[i][0],&so[i][1]);	//输入左儿子和右儿子

Step 2:判断一棵树是否“对称”。我们以“左儿子与右儿子的节点数和权值是否相等”“左儿子的左儿子和右儿子的右儿子节点数和权值是否相等”……等条件来递归地判断,只要当一个条件不满足,终止递归,返回不对称。
Step 2-1:计算一课树的节点数。

int sum(int root){					//root为当前递归计算的树
	int l=so[root][0],r=so[root][1];//l为当前节点的左儿子,r为当前节点的右儿子
	if(l==-1&&r==-1)return 1;		//当root没有儿子时,返回1,因为只有root一个节点
	if(l==-1)return 1+sum(r);		//如果没有左儿子,就返回当前这一个节点加上右儿子的大小
	if(r==-1)return 1+sum(l);		//如果没有右儿子,就返回当前这一个节点加上左儿子的大小
	return sum(l)+sum(r)+1;			//否则返回当前结点加上左儿子和右儿子大小的和
}									//之前把函数返回类型写成bool了,找了半天没找到错QAQ

Step 2-2:判断对称。

bool ck(int l,int r){			//l和r为当前判断的对称轴左边的树和右边的树
	if(l==-1&&r==-1)return 1;	//如果左边和右边都没有,肯定对称
	if(c[l]!=c[r])return 0;  	//如果左边权值≠右边权值,不对称
	if(sum(l)!=sum(r))return 0;	//如果左右两边大小不相等,不对称
	return ck(so[l][0],so[r][1])&&ck(so[l][1],so[r][0]);
	//递归判断,如果左边的左边与右边的右边对称,且左边的右边与右边的左边对称,才能判断当前层对称。
}

Step 3:从1~n判断是否对称,用ans存储最大值。

原思路完整代码

啊对了,此处千万不能加快读,否则会多T一个点(玄学啊TAT)

点我

(#`O′)喂!lemon你出来解释一下!四个 1 e 6 1e6 1e6 的数组很大吗?超 216 M i B 216MiB 216MiB 了吗?(小声:是挺大的,貌似已经擦边了。。。
计算器:4*1e6 数组=32000000B,256MiB=33554432B。。。)

生气.jpg

改正后的思路

话说洛谷的代码公开计划真好用,因为分数在80以上,可以看到别人的AC代码~

大概就是Step 2-1出现了问题,计算sum的时候我们用s数组存结果,在Step 2-2之前遍历整棵树,这样就不用在每次判断是否对称时重新递归一次,直接用结果,节省了很多时间。

本来考试的时候想到了的,可惜看漏了这么一句:

第一行一个正整数 n n n,表示给定的树的节点的数目,规定节点编号 1 ∼ n 1 \sim n 1n其中节点 1 1 1 是树根

所以一直担心从哪个节点开始遍历整棵树,会不会爆空间等,一直不敢试。(结果你还不是MLE了!)

所以只需要把sum内部稍稍改一下,在输入后调用一下sum函数,再把其他每个地方的sum(x)换成s[x]即可,如果你保证你上面都看懂了,那么你把84分代码改AC应该只需要不到一分钟。

事后诸葛

AC代码仅限洛谷!!

其他OJ貌似会MLE(空间限制256MiB的就算了,毕竟擦边了嘛,但512MiB的空间限制还MLE是几个意思!?)

不点个赞👍🏻再走嘛?

求你

posted @ 2020-08-27 23:01  XSC062  阅读(83)  评论(0编辑  收藏  举报