开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情
- 559.n叉树的最大深度
- 226.翻转二叉树
- 101.对称二叉树
559.n叉树的最大深度
题目链接:N 叉树的最大深度
给定一个 N 叉树,找到其最大深度。最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。
思路:就是N叉树的层序遍历写法(用到了 for (let item of node.children) { }),再加上二叉树的最大深度写法。
var maxDepth = function (root) {
// 最大的深度就是二叉树的层数
if (root === null) return 0;
let queue = [root];
let height = 0;
while (queue.length) {
let n = queue.length;
height++;
for (let i = 0; i < n; i++) {
let node = queue.shift();
for (let item of node.children) {
item && queue.push(item);
}
}
}
return height;
};
226.翻转二叉树
题目链接:翻转二叉树
递归法
思路以及代码
首先要注意,想要返回的数据类型是节点,并不是数组!所以我一开始的思路(遍历每一层节点值,然后翻转数据压入数组,最后进行一个 res 二维数组的扁平化)是行不通的!!
这一题关键在于,选择前中后序哪一种遍历方式? 使用前序遍历和后序遍历都可以,然后把每一个节点的左右孩子反转一下。
- 确定递归函数的参数和返回值
- 确定终止条件:当前节点为空的时候,就返回
- 确定单层递归的逻辑:因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。
var invertTree = function(root) {
// 终止条件
if (!root) {
return null;
}
// 交换左右节点
const rightNode = root.right;
root.right = invertTree(root.left);
root.left = invertTree(rightNode);
return root;
};
层序遍历法
思路以及代码
使用层序遍历,就要先定义好节点交换函数
var invertTree = function (root) {
// 节点交换函数
const invertNode = function (root, left, right) {
let temp = left;
left = right;
right = temp;
root.left = left;
root.right = right;
}
if (root === null) return root;
let queue = [];
queue.push(root);
while (queue.length) {
// 记录当前层数的节点数
let n = queue.length;
while (n--) {
let node = queue.shift();
invertNode(node, node.left, node.right);
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
}
// 二维数组扁平化处理
return root
};
let temp = left;那么这个 temp 装的就是当前的 左节点,记住类型是节点。- 接下来一步的
root.left = left;就是将当前的root的左孩子指向交换后的左节点。如果没有这一步,root还是原来的那个root。
101.对称二叉树
题目链接:对称二叉树
比较的是根节点的两个子树是否是相互翻转的
递归法
因为需要不断收集左右子树的信息,然后返回给上一层,所以这里要使用
后序遍历(左右根)
-
确定递归函数的参数和返回值
- 比较根节点下面的两个树,参数自然也是左子树节点和右子树节点。返回值自然是bool类型。
-
确定终止条件
-
要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚!否则后面比较数值的时候就会操作空指针了。
-
节点为空的情况有:(注意我们比较的其实不是左孩子和右孩子,所以如下我称之为左节点右节点)
- 左节点为空,右节点不为空,不对称,return false
- 左不为空,右为空,不对称 return false
- 左右都为空,对称,返回true
-
此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:
- 左右都不为空,比较节点数值,不相同就return false
-
此时左右节点不为空,且数值也不相同的情况我们也处理了。
-
-
确定单层递归的逻辑 处理 左右节点都不为空,且数值相同的情况。
- 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
- 比较内测是否对称,传入左节点的右孩子,右节点的左孩子。
- 如果左右都对称就返回true ,有一侧不对称就返回false 。
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);
};
迭代法
使用队列来比较两个树(根节点的左右子树)是否相互翻转。
注意这不是层序遍历,且由于题目需求,不能使用平常的前中后序遍历了。已经不是所谓二叉树遍历的前中后序的关系了。
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;
}
// 左右一个节点不为空,或者都不为空但数值不相同,返回false
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;
};
所以在这样不断while循环的过程中,就能判断相对应位置的节点是否相同!