【题目链接】
ybt 1981:【18NOIP普及组】对称二叉树
洛谷 P5018【NOIP2018 普及组】 对称二叉树
【题目考点】
- 二叉树
【解题思路】
- 先求出二叉树中各子树的结点数
- 遍历二叉树,判断每个子树是否是对称二叉树
- 判断一个二叉树是否是对称二叉树:
- 对称变换:将该树中所有结点的左右子树交换。显然,一棵树经过两次对称变换后,会变为原来的树。
- 两树对称:如果树1经过对称变换可以变为树2,那么称树1与树2对称。显然,树1与树2对称时,树2与树1对称。
- 如果一个二叉树是对称二叉树,那么其左子树应该与右子树对称。
- 证明:二叉树是对称的,那么其经过对称变换后的左子树,是由原右子树变换过来的。已知对称变换后的树与原树相同,那么变换后的左子树与原左子树相同,那么原左子树与原右子树是对称的。
- 设函数check(),参数为树1、树2两棵树的根,该函数判断树1、树2是否对称。
- 判断两棵树是否对称:
- 如果两棵树都是空树(根结点地址都为-1),那么它们是对称的。
- 如果两棵树都不是空树,同时满足如下条件时,二者才是对称的
- 两棵树根结点的权值应该相同
- 两棵树的结点数应该相同
- 树1的左子树应该与树2右子树对称。
- 树1的右子树应该与树2的左子树对称
【题解代码】
解法1:
#include<bits/stdc++.h>
using namespace std;
#define N 1000005
typedef struct Node
{
int val, left, right;//val:权值, left:左孩子地址 right:右孩子地址
}Node;
Node tree[N];//tree[i],为id为i的结点
int treeNodeNum[N];//treeNodeNum[i]保存id为i的结点的子树的结点数。
int n;
int mxNodeNum;//结点数量最大的对称子树的结点数
//判断以root1为根的子树和以root2为根的子树是否对称
bool check(int root1, int root2)
{
if(root1 == -1 && root2 == -1)//空结点,相同
return true;
else if(root1 != -1 && root2 != -1 && //左右子树都有结点
tree[root1].val == tree[root2].val && //树根结点权相同,
treeNodeNum[root1] == treeNodeNum[root2] && //树结点数相同
check(tree[root1].left, tree[root2].right) && //经过对称变换后,root2树的右子树应该与root1树的左子树对称
check(tree[root1].right, tree[root2].left))//经过对称变换后,root2树的左子树应该与root1树的右子树对称
return true;
else
return false;
}
//获取树的结点数
int getNodeNum(int root)
{
if(root == -1)
return 0;
else
{
int nodeNum = getNodeNum(tree[root].left) + getNodeNum(tree[root].right) + 1;
treeNodeNum[root] = nodeNum;
return nodeNum;
}
}
//确定结点最多的对称的子树的结点数
void Search(int root)
{
if(root != -1)
{
if(treeNodeNum[root] <= mxNodeNum)//剪枝,如果当前子树的结点数已经比获得的最大对称子树结点数要小,那么没必要再搜索下去。
return;
if(check(tree[root].left, tree[root].right))//如果树root是对称的,那么其左右子树对称
mxNodeNum = treeNodeNum[root];//如果对称,记录结点数。由于已有剪枝操作,此时treeNodeNum[root]一定大于mxNodeNum
else
{
Search(tree[root].left);
Search(tree[root].right);
}
}
}
int main()
{
scanf("%d\n", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &tree[i].val);
for(int i = 1; i <= n; ++i)
scanf("%d %d", &tree[i].left, &tree[i].right);
getNodeNum(1);//初始化树的各子树结点数
Search(1);//从根结点开始,遍历所有子树,找出对称子树,并看其结点数,保存最大结点数
printf("%d", mxNodeNum);
return 0;
}