开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情
- 429.N叉树的层序遍历
- 515.在每个树行中找最大值
- 116.填充每个节点的下一个右侧节点指针
- 二叉树的最大深度
- 二叉树的最小深度
429.N叉树的层序遍历
题目链接:N 叉树的层序遍历
给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。
思路:由于这是N叉树,所以一个节点下面不一定有两个子节点。那么这题就不能用node.left和node.right。题目中已经给定了类 Node ,其中含有属性:val 、 children 。
代码:
var levelOrder = function (root) {
let res = [], queue = [];
queue.push(root);
while (queue.length && root !== null) {
// 记录每一层节点个数
let length = queue.length;
// 存放每层节点,也和二叉树一致
let curLevel = [];
while (length--) {
let node = queue.shift();
curLevel.push(node.val);
// 这里不再是左右子节点了,而是循环node.children
for (let item of node.children) {
item && queue.push(item);
}
}
res.push(curLevel);
}
return res;
};
while (length--) { }换成for (let i = 0; i < length; i++) { }也可以运行
515.在每个树行中找最大值
题目链接:在每个树行中找最大值
思路以及代码
方法一:还是使用层序遍历的代码,之前是每层遍历完的结果是放到curLevel里面,然后再放到结果里。现在是直接找出数组curLevel里面的最大值,然后放到结果里面。
var largestValues = function (root) {
let res = [], queue = [];
queue.push(root);
while (queue.length && root !== null) {
let length = queue.length;
let curLevel = [];
while (length--) {
let node = queue.shift()
curLevel.push(node.val);
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
let max = Math.max(...curLevel);
res.push(max)
}
return res;
};
方法二:将max的初始值设为队列的第一个元素,然后再遍历后续元素的时候,不断比较和更新max的数值。
var largestValues = function (root) {
//使用层序遍历
let res = [], queue = [];
queue.push(root);
while (root !== null && queue.length) {
//设置max初始值就是队列的第一个元素
let max = queue[0].val;
let length = queue.length;
while (length--) {
let node = queue.shift();
max = max > node.val ? max : node.val;
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
//把每一层的最大值放到res数组
res.push(max);
}
return res;
};
116.填充每个节点的下一个右侧节点指针
题目链接:填充每个节点的下一个右侧节点指针
思路以及代码
由于本题不需要得到一定结果集,所以这里也不用定义res。只不过在单层遍历的时候记录一下本层的头部节点,然后在遍历的时候让前一个节点指向本节点就可以了
var connect = function(root) {
if (root === null) return root;
let queue = [root];
while (queue.length) {
let n = queue.length;
for (let i=0; i<n; i++) {
let node = queue.shift();
if (i < n-1) {
node.next = queue[0];
}
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
}
return root;
};
if (i < n-1) { node.next = queue[0]; }在层序遍历那一题中,会用curLevel.push(node.val)存入每层的节点。但是现在用代码中的 if 语句,就能实现让前一个节点指向本节点了。
104.二叉树的最大深度
题目链接:二叉树的最大深度
对于二叉树中的某个节点,其深度是从根节点到该节点的最长简单路径所包含的节点个数,是从上面向下面数的。
思路及代码
方法一:使用层序遍历是最为合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。
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();
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
}
return height;
};
方法二:使用递归法
借用参考文章里面大佬的分析:
- 递归函数的返回值和参数:返回值为当前节点的最大深度,参数为当前节点
- 递归函数的单层逻辑:当前节点的最大深度 = 1 + 左子树或右子树的最大深度
- 递归函数的终止条件:当前节点为空时,当前节点最大深度为0
var maxDepth = function (root) {
// 递归终止条件
if (root === null) return 0;
// 单层递归逻辑
let leftDepth = maxDepth(root.left);
let rightDepth = maxDepth(root.right);
return 1 + Math.max(leftDepth, rightDepth);
};
111.二叉树的最小深度
题目链接:二叉树的最小深度
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
思路及代码
方法一:需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点
var minDepth = function (root) {
if (root === null) return 0;
let queue = [root];
let depth = 0;
while (queue.length) {
let n = queue.length;
depth++;
for (let i = 0; i < n; i++) {
let node = queue.shift();
// 如果左右节点都是null(在遇见的第一个leaf节点上),则该节点深度最小
if (node.left === null && node.right === null) {
return depth;
}
node.left && queue.push(node.left);;
node.right && queue.push(node.right);
}
}
return depth;
};
方法二:递归法。
var minDepth = function(root) {
// 递归终止条件
if (root === null) return 0;
// 单层递归逻辑
let leftDepth = minDepth(root.left);
let rightDepth = minDepth(root.right);
// 单个子树为空的处理
if (root.left && !root.right) return 1 + leftDepth;
if (!root.left && root.right) return 1 + rightDepth;
// 两个子树均不为空的处理
return 1 + Math.min(leftDepth, rightDepth);
};