项目地址:https://github.com/SpecialYy/Sword-Means-Offer
问题
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
解析
首先要理解对称二叉树是个什么样子的,如下图就是一个简单的对称的二叉树。
通过上图,我们很容易可以发现对称二叉树的特性:
- 对原二叉树进行翻转,得到新的二叉树在值表现形式是不变,也就是题目说的若二叉树与二叉树的镜像是一致的,那么它就是对称二叉树。
- 我们可以发现左子树中节点的左孩子与右子树中节点的右孩子的值是一样,且左子树中节点的右孩子与右子树中节点的左孩子的值是一样的。
- 左右子树的叶子节点是完全一致的
思路一
思路一完全利用的就是特性2和3,在一般的二叉树遍历的过程中,我们都是先遍历左子树后遍历右子树。在这个题目中,为了同时判断左右子树的值相等情况,我们同时遍历左右子树。从根节点的左孩子和右孩子开始,同时遍历根节点的左子树和右子树。对于遍历到的左子树中节点A和右子树中的节点B,我们判断是否值相同,若相同, 则继续遍历A的左孩子和B的右孩子,然后再遍历A的右孩子和与B的左孩子;若不相同,说明该树从当前层以下都是非对称的,也就说整棵树都不是对称了,此时停止遍历,向上回溯,返回false。
还是以上图的为例,解释下过程:
- 首先是从根节点1的左孩子2和右孩子2开始遍历
- 判断当前遍历到节点值是否相同,当前遍历的节点的值都为2,所以继续遍历,左子树这边遍历当前的节点的左孩子3,右子树这边遍历当前的节点的右孩子3
- 判断当前遍历到节点值是否相同,当前遍历的节点的值都为3,所以继续遍历,左子树这边遍历当前的节点的左孩子null,右子树这边遍历当前的节点的右孩子null
- 当前遍历的节点都是同时走到空节点,所以向上返回true,表示在这条遍历线上是对称。回到上层后,继续遍历,左子树这边遍历当前的节点的右孩子null,右子树这边遍历当前的节点的左孩子null
- 当前遍历的节点都是同时走到空节点,所以向上返回true,表示在这条遍历线上是对称。回到上层后,继续遍历,左子树这边遍历当前的节点的右孩子4,右子树这边遍历当前的节点的左孩子4
- 判断当前遍历到节点值是否相同,这里他们都是叶子节点,后续的过程与3,4,5一致。
- 回溯到最上层,返回true,表明是一颗对称二叉树。
boolean isSymmetrical(TreeNode pRoot) {
if (pRoot == null) {
return true;
}
//考察左子树和右子树是否对称的
return isSymmetrical(pRoot.left, pRoot.right);
}
boolean isSymmetrical(TreeNode node1, TreeNode node2) {
//递归结束条件,左子树的节点和右子树的节点都已遍历到叶子节点
if (node1 == null && node2 == null) {
return true;
}
//判断当前遍历到的节点的值是否相同
if (node1 != null && node2 != null
&& node1.val == node2.val) {
/**
* 若相同,则继续考察节点1的左孩子和节点2的右孩子是否相同
* 节点1的右孩子和节点2的左孩子是否相同
*/
return isSymmetrical(node1.left, node2.right) &&
isSymmetrical(node1.right, node2.left);
}
/**
* 当前节点的值不相同,返回false,上层函数由于&&的短路特性
* 则不再递归,直到回溯到最开始
*/
return false;
}