题目描述:
请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
解题思路:
1、一开始我使用的方法,是层次遍历,存入列表中,遍历的时候左右子树顺序交换一下,然后得到两个List集合,对比。但是这样没考虑子树为空的情况,导致虽然不符合题目要求,但是还是错误判断成了符合。
2、另一种方法,是比较两棵树是不是相同,一个树是复制它本身,另一个树是这个树本身的镜像。
这里有三个常见的用法:
- 复制本身
//复制二叉树
public TreeNode CopyTree(TreeNode node)
{
if( null == node)return null;
TreeNode copy = new TreeNode(node.val);
copy.left = CopyTree(node.left);
copy.right = CopyTree(node.right);
return copy;
}
- 树的镜像
//镜像
public TreeNode mirror(TreeNode treeNode)
{
if(treeNode==null)
return treeNode;
TreeNode temp;
temp=treeNode.left;
treeNode.left=treeNode.right;
treeNode.right=temp;
mirror(treeNode.left);
mirror(treeNode.right);
return treeNode;
}
- 比较两个二叉树是否相同
//判断两个二叉树是否相等
public boolean equal(TreeNode treeNode,TreeNode treeNode2)
{
if(treeNode==null&&treeNode2==null)
return true;
if(treeNode==null||treeNode2==null)
return false;
if(treeNode.val!=treeNode2.val)
return false;
return equal(treeNode.left,treeNode2.left)&&equal(treeNode.right,treeNode2.right);
}
所有完整代码为:
boolean isSymmetrical2(TreeNode pRoot)
{
TreeNode root1=CopyTree(pRoot);//复制原二叉树
TreeNode root2=mirror(pRoot);//镜像二叉树
return equal(root1,root2);//比较
}
//镜像
public TreeNode mirror(TreeNode treeNode)
{
if(treeNode==null)
return treeNode;
TreeNode temp;
temp=treeNode.left;
treeNode.left=treeNode.right;
treeNode.right=temp;
mirror(treeNode.left);
mirror(treeNode.right);
return treeNode;
}
//复制二叉树
public TreeNode CopyTree(TreeNode node)
{
if( null == node)return null;
TreeNode copy = new TreeNode(node.val);
copy.left = CopyTree(node.left);
copy.right = CopyTree(node.right);
return copy;
}
//判断两个二叉树是否相等
public boolean equal(TreeNode treeNode,TreeNode treeNode2)
{
if(treeNode==null&&treeNode2==null)
return true;
if(treeNode==null||treeNode2==null)
return false;
if(treeNode.val!=treeNode2.val)
return false;
return equal(treeNode.left,treeNode2.left)&&equal(treeNode.right,treeNode2.right);
}
接着思考,我们在比较过程中,两个树是利用递归,一个一个比较左右子树是否相等得到的,那么我们是不是可以把比较的条件换一下,然后直接让树的自身和自身相比较,这样,就省去了二叉树镜像的转换。所以优化后的代码如下
//这种方法在比较的时候直接利用递归指向左右不同子树比较,省去了把树转换成镜像的一步
boolean isSymmetrical3(TreeNode pRoot)
{
TreeNode copy=copy(pRoot);
return isSameTree(copy,pRoot);
}
//复制二叉树
public TreeNode copy(TreeNode treeNode)
{
if(treeNode==null)
return null;
TreeNode copy=new TreeNode(treeNode.val);
copy.left=copy(treeNode.left);
copy.right=copy(treeNode.right);
return copy;
}
boolean isSameTree(TreeNode treeNode1,TreeNode treeNode2)
{
if(treeNode1==null&&treeNode2==null)
return true;
if(treeNode1==null||treeNode2==null)
return false;
if(treeNode1.val!=treeNode2.val)
return false;
return isSameTree(treeNode1.left,treeNode2.right)&&isSameTree(treeNode1.right,treeNode2.left);
}
再接着思考,我们在比较的过程中是需要两棵树的,但是一棵树的根节点是什么都不影响左右子树的对称性,所以我们是不是在比较的时候就可以把两棵树换成传入树的左右子树,这样我们就又省去了复制二叉树的步骤。
代码如下:
//继续优化,不复制树
boolean isSymmetrical4(TreeNode pRoot)
{
//这里注意一下传入空的时候,加一个条件使返回true,否则会抛出空指针异常
return pRoot==null||isSameTree2(pRoot.left,pRoot.right);
}
boolean isSameTree2(TreeNode treeNode1,TreeNode treeNode2)
{
if(treeNode1==null&&treeNode2==null)
return true;
if(treeNode1==null||treeNode2==null)
return false;
if(treeNode1.val!=treeNode2.val)
return false;
return isSameTree(treeNode1.left,treeNode2.right)&&isSameTree(treeNode1.right,treeNode2.left);
}