题目三:
解法一:(递归)
解题思路:参考代码随想录,整体就相当于左右子树对称镜像位置一个一个比较。
递归三部曲
- 确定递归函数的参数和返回值
因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。
返回值自然是bool类型。
代码如下:
const compare = function (left, right){}
- 确定终止条件
要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚!否则后面比较数值的时候就会操作空指针了。
节点为空的情况有:(注意我们比较的其实不是左孩子和右孩子,所以如下我称之为左节点右节点)
- 左节点为空,右节点不为空,不对称,return false
- 左不为空,右为空,不对称 return false
- 左右都为空,对称,返回true
此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:
- 左右都不为空,比较节点数值,不相同就return false
此时左右节点不为空,且数值也不相同的情况我们也处理了。
代码如下:
if (left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
else if (left->val != right->val) return false; // 注意这里我没有使用else
注意上面最后一种情况,我没有使用else,而是elseif, 因为我们把以上情况都排除之后,剩下的就是 左右节点都不为空,且数值相同的情况。
- 确定单层递归的逻辑
此时才进入单层递归的逻辑,单层递归的逻辑就是处理 左右节点都不为空,且数值相同的情况。
- 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
- 比较内测是否对称,传入左节点的右孩子,右节点的左孩子。
- 如果左右都对称就返回true ,有一侧不对称就返回false 。
代码如下:
bool outside = compare(left.left, right.right); // 左子树:左、 右子树:右
bool inside = compare(left.right, right.left); // 左子树:右、 右子树:左
bool isSame = outside && inside; // 左子树:中、 右子树:中(逻辑处理)
return isSame;
如上代码中,我们可以看出使用的遍历方式,左子树左右中,右子树右左中,所以我把这个遍历顺序也称之为“后序遍历”(尽管不是严格的后序遍历)
var isSymmetric = function(root) {
//使用递归遍历左右子树 递归三部曲
// 1. 确定递归的参数 root.left root.right和返回值true false
const compareNode=function(left,right){
//2. 确定终止条件 空的情况
if(left===null&&right!==null||left!==null&&right===null){
return false;
}else if(left===null&&right===null){
return true;
}else if(left.val!==right.val){
return false;
}
//3. 确定单层递归逻辑
let outSide=compareNode(left.left,right.right);
let inSide=compareNode(left.right,right.left);
return outSide&&inSide;
}
if(root===null){
return true;
}
return compareNode(root.left,root.right);
};
// 或者
const isSymmetric = (root) => {
const check = (left, right) => {
if (left == null && right == null) { // 两个子树都为null,是对称的
return true;
}
if (left && right) { // 两个子树都存在,则需要:root值相同,且他们的子树也满足镜像
return left.val == right.val && check(left.left, right.right) && check(left.right, right.left);
}
return false; // 一个子树存在一个不存在,肯定不对称
};
if (root == null) { // 如果传入的root就是null,对称
return true;
}
return check(root.left, root.right); // 否则,判断它的左右子树是否满足对称
}
解法二:(队列)
队列实现迭代判断是否为对称二叉树:
var isSymmetric = function (root) {
//迭代方法判断是否是对称二叉树
//首先判断root是否为空
if (root === null) {
return true
}
let queue = []
queue.push(root.left)
queue.push(root.right)
while (queue.length) {
let leftNode = queue.shift() //左节点
let rightNode = queue.shift() //右节点
if (leftNode === null && rightNode === null) {
continue
}
if ( leftNode === null || rightNode === null || leftNode.val !== rightNode.val) {
return false
}
queue.push(leftNode.left) //左节点左孩子入队
queue.push(rightNode.right) //右节点右孩子入队
queue.push(leftNode.right) //左节点右孩子入队
queue.push(rightNode.left) //右节点左孩子入队
}
return true
}
解法三:(栈)
栈实现迭代判断是否为对称二叉树:
var isSymmetric = function(root) {
// 迭代方法判断是否是对称二叉树
// 首先判断root是否为空
if(root === null){
return true;
}
let stack=[];
stack.push(root.left);
stack.push(root.right);
while (stack.length){
let rightNode = stack.pop();//右节点
let leftNode = stack.pop();//左节点
if(leftNode === null && rightNode === null){
continue;
}
if(leftNode === null || rightNode === null || leftNode.val !== rightNode.val){
return false;
}
stack.push(leftNode.left);//左节点左孩子入队
stack.push(rightNode.right);//右节点右孩子入队
stack.push(leftNode.right);//左节点右孩子入队
stack.push(rightNode.left);//右节点左孩子入队
}
return true;
};
解法四:(中序遍历+层数)
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isSymmetric = function (root) {
if (root == null) {
return true;
}
//左中右顺序递归二叉树
var nums = [];
search(nums, root, 1);
//判断是否对称
var i = 0, j = nums.length - 1;
while (i < j) {
if (nums[i] != nums[j]) {
return false;
}
i++;
j--;
}
return true;
};
/**
* 按照左中右顺序递归二叉树,输出至数组nums中
* @param nums 输出
* @param n 节点
* @param k 层次
*/
function search(nums, n, k) {
//左边
if (n.left != null) {
search(nums, n.left, k + 1);
}
//节点值,层次
nums.push(n.val + ',' + k);
//右边
if (n.right != null) {
search(nums, n.right, k + 1);
}
}
我最开始考虑的就是中序遍历,最后判断数组是否对称,但是对于特殊null的情况并没有想到如何考虑,参考别人的想法,可以加上层数,很不错。