what.什么是对称二叉树?
对称二叉树,本质上就是从二叉树的根节点开始,左子节点的值和右子节点的值相等,并且左子节点的左子节点和右子节点的右子节点的值相等,左子节点的右子节点和右子节点的左子节点的值相等,继续向下遍历,依然满足上述规则。
不方便理解的话,看图说话~
对称二叉树
非对称二叉树
how.怎么判断二叉树是否对称?
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
// 递归
var isSymmetric = function(root) {
// 如果根节点为空节点,则该二叉树为对称二叉树
if (!root) {
return true;
}
// 借助辅助函数判断二叉树是否为对称二叉树,传入左子节点和右子节点作为参数
return isSymmetricHelper(root.left, root.right);
};
var isSymmetricHelper = function(left, right) {
// 如果左子节点和右子节点都为空节点,说明当前节点为叶子结点,返回true
// 在后续的递归判断中,这里表示左子节点的右子节点和右子节点的左子节点(或左子节点的右子节点和右子节点的左子节点)都为null,即相等,返回true
if (!left && !right) {
return true;
}
// 如果左子节点或右子节点为空,或者左子节点和右子节点的值不相等,则说明该二叉树不是对称二叉树,返回false
if (left === null || right === null || left.val !== right.val) {
return false;
}
// 如果上面的判断条件都没有拦截住的话,说明左子节点和右子节点的值相等,进而利用辅助函数继续判断左子节点的左子节点和右子节点的右子节点,左子节点的右子节点和右子节点的左子节点是否相等
return isSymmetricHelper(left.left, right.right) && isSymmetricHelper(left.right, right.left)
}
// 非递归
var isSymmetric = function (root) {
// 如果根节点为空,该二叉树也为对称二叉树,返回true
if (!root) {
return true;
}
// 如果根节点不为空,维护一个队列,用于存储二叉树的每一个子节点,初始化是依次放入根节点的左子节点和右子节点
const queue = [root.left, root.right];
// 执行循环,直到队列为空
while (queue.length) {
// 队列中的前两项依次出列,分别作为left和right变量的值
let left = queue.shift(),
right = queue.shift();
// 如果left和right为空,则继续执行下一次循环
if (!left && !right) {
continue;
}
// 如果left和right其一为空,或者left和right的val属性值不相等,则结束循环并返回false
if (!left || !right || left.val !== right.val) {
return false;
}
// 如果上述判断都没有拦截到,则说明当前比较的两个子节点符合对称二叉树子节点的要求,并按顺序将左子节点的左子节点,右子节点的右子节点,左子节点的右子节点和右子节点的左子节点依次入列
queue.push(left.left);
queue.push(right.right);
queue.push(left.right);
queue.push(right.left);
}
// 如果循环结束后,没有任何判断拦截并返回,则说明该二叉树符合对称二叉树的要求,返回true
return true;
}