102. 二叉树的层序遍历
题目:
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
思路:
利用队列,设置两层循环,第一层循环判断条件为队列是否为空,然后在循环内部用一个变量size获取队列长度,声明一个数组,存储当前层数的元素,设置第二层循环判断条件是当前队列长度,每次判断结束size--,在循环内部获取队列的头部节点,推入数组中,然后判断分别当前节点是否有左右节点,如果有推入队列中,最后把当前数组推入结果数组中,最后在循环外输出结果数组。
代码:
/**
* 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 {number[][]}
*/
var levelOrder = function(root) {
const queue = [],res = []
root&&queue.push(root)
while (queue.length) {
let size = queue.length
const arr = []
while (size--) {
let node = queue.shift()
arr.push(node.val)
node.left&&queue.push(node.left)
node.right&&queue.push(node.right)
}
res.push(arr)
}
return res
};
总结:
做完了二叉树的前中后序遍历后后,再来看层序遍历,感觉简单了很多。
107. 二叉树的层序遍历 II
题目:
给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
思路:
和102层序遍历一样,最后输出的时候把结果数组逆序
代码:
/**
* 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 {number[][]}
*/
var levelOrderBottom = function(root) {
const queue = [],res = []
root&&queue.push(root)
while (queue.length) {
let size = queue.length
const arr = []
while (size--) {
let node = queue.shift()
arr.push(node.val)
node.left&&queue.push(node.left)
node.right&&queue.push(node.right)
}
res.push(arr)
}
return res.reverse()
};
199. 二叉树的右视图
题目:
给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
思路:
在将每层元素推入当前层数数组的时候,判断当前size是否为0,即判断当前元素是否为该层的最后一个元素,如果是,那就推入当前层数数组。
代码:
/**
* 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 {number[]}
*/
var rightSideView = function(root) {
const queue = [],res = []
root&&queue.push(root)
while (queue.length) {
let size = queue.length
while (size--) {
let node = queue.shift()
size===0&&res.push(node.val)
node.left&&queue.push(node.left)
node.right&&queue.push(node.right)
}
}
return res
};
总结:
一开始想只在队列中存入右节点,后来变成先判断是否有右节点,如果没有就存入左节点,结果发现不能判断下一层的左节点,总之说来说去逻辑就只有一句话,就是判断当前元素是否为最右边的节点。
637. 二叉树的层平均值
题目:
给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。
思路:
很简单,把每层数组替换成当前数组内元素总和除以元素个数,即求当前层的平均值,然后再推入结果数组中输出。
代码:
/**
* 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 {number[]}
*/
var averageOfLevels = function(root) {
const queue = [],res = []
root&&queue.push(root)
while (queue.length) {
let size = queue.length
const arr = [],device = size
while (size--) {
let node = queue.shift()
arr.push(node.val)
node.left&&queue.push(node.left)
node.right&&queue.push(node.right)
}
let sum = arr.reduce((sum,num)=>sum+num,0)
// console.log(sum/size)
res.push(parseFloat(sum/device))
}
return res
};
429. N 叉树的层序遍历
题目:
给定一个 N 叉树,返回其节点值的_层序遍历_。(即从左到右,逐层遍历)。 树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。
思路:
在遍历每层元素的时候额外添加一个for循环,把children里的每个子元素单独添加到队列中。
代码:
/**
* // Definition for a Node.
* function Node(val,children) {
* this.val = val;
* this.children = children;
* };
*/
/**
* @param {Node|null} root
* @return {number[][]}
*/
var levelOrder = function(root) {
const queue = [],res = []
root&&queue.push(root)
while (queue.length) {
let size = queue.length
const arr = []
while (size--) {
let node = queue.shift()
arr.push(node.val)
for (let i = 0; i< node.children.length;i++) {
node.children[i]&&queue.push(node.children[i])
}
}
res.push(arr)
}
return res
};
515. 在每个树行中找最大值
题目:
给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。
思路:
把每层数组替换成每层数组中的最大值然后推入结果数组最后输出。
代码:
/**
* 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 {number[]}
*/
var largestValues = function(root) {
const queue = [],res = []
root&&queue.push(root)
while (queue.length) {
let size = queue.length
const arr = []
while (size--) {
let node = queue.shift()
arr.push(node.val)
node.left&&queue.push(node.left)
node.right&&queue.push(node.right)
}
res.push(Math.max(...arr))
}
return res
};
116. 填充每个节点的下一个右侧节点指针
题目:
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
思路:
利用层序遍历,判断如果当前元素指向不是最后一个元素,就把这个元素的next指针指向下一个元素,也就是队列的队头元素。
代码:
/**
* // Definition for a Node.
* function Node(val, left, right, next) {
* this.val = val === undefined ? null : val;
* this.left = left === undefined ? null : left;
* this.right = right === undefined ? null : right;
* this.next = next === undefined ? null : next;
* };
*/
/**
* @param {Node} root
* @return {Node}
*/
var connect = function(root) {
const queue = []
root&&queue.push(root)
while (queue.length) {
let size = queue.length
for (let i = 0;i<size;i++) {
let node = queue.shift()
if (i<size-1) {
node.next = queue[0]
}
node.left&&queue.push(node.left)
node.right&&queue.push(node.right)
}
}
return root
};
总结:
自己写的时候总是在想是不是要设置一个指针,去指向前一个元素,然后用前一个元素的next指向当前的元素,非常复杂,其实下一个元素就是当前队列的队头元素。
117. 填充每个节点的下一个右侧节点指针 II
题目:
总结:
和上一题没区别
104. 二叉树的最大深度
题目:
给定一个二叉树,找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。
思路:
把每层数组放入结果数组输出替换成一个计数器,然后输出计数器
代码:
/**
* 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 {number}
*/
var maxDepth = function(root) {
const queue = []
let count =0
root&&queue.push(root)
while (queue.length) {
let size = queue.length
while (size--) {
let node = queue.shift()
node.left&&queue.push(node.left)
node.right&&queue.push(node.right)
}
count++
}
return count
};
总结:
比较简单。
111. 二叉树的最小深度
题目:
给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明:叶子节点是指没有子节点的节点。
思路:
判断如果一个节点没有左节点且没有右节点就直接返回深度,最后再输出一下深度以免该树只有一个分支
代码:
/**
* 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 {number}
*/
var minDepth = function(root) {
const queue = []
let count =0
root&&queue.push(root)
while (queue.length) {
let size = queue.length
count++
while (size--) {
let node = queue.shift()
if (!node.left&&!node.right) {
return count
}
node.left&&queue.push(node.left)
node.right&&queue.push(node.right)
}
}
return count
};
总结:
一开始写的时候把判断输出的顺序弄错了,弄到添加左右节点的后面,放在前面就没问题了。
226. 翻转二叉树
题目:
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
思路:
- 递归:
- 先设置参数和返回值分别是左右节点,最后返回根节点
- 先设置退出递归的条件,即当前节点为null
- 设置单层逻辑,调换左右节点位置,然后向下寻找节点
- 迭代:
- 利用栈每次取出栈顶元素,判断是否存在,存在就向下寻找节点,按先序放入栈中,不存在就取出上一个节点元素进行逻辑操作
- 层序遍历:
- 利用队列,每次取出队头元素进行逻辑操作,向下寻找节点,从队尾插入
代码:
/**
* 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 {TreeNode}
*/
// 递归
var invertTree = function(root) {
if (root === null) return root
let node = root.right
root.right = invertTree(root.left)
root.left = invertTree(node)
return root
};
// 统一迭代
var invertTree = function(root) {
if (root === null) return root
const stack = [root]
while (stack.length) {
let node = stack.pop()
if (node) {
if (node.right) stack.push(node.right)
if (node.left) stack.push(node.left)
stack.push(node)
stack.push(null)
}else {
node = stack.pop()
let nodeRight = node.right
node.right = node.left
node.left = nodeRight
}
}
return root
};
// 层序遍历
var invertTree = function(root) {
if (root === null) return root
const queue = [root]
while (queue.length) {
let size = queue.length
while(size--){
const node = queue.shift()
let tmp = node.right
node.right = node.left
node.left = tmp
node.left && queue.push(node.left)
node.right && queue.push(node.right)
}
}
return root
};
总结:
逻辑不难,但是细节要琢磨清楚。
101. 对称二叉树
题目:
给你一个二叉树的根节点 root , 检查它是否轴对称。
思路:
- 递归:
- 设置传入参数和返回值,参数是左右节点,返回布尔值
- 设置退出递归条件,如果不对称返回false,对称返回true
- 设置单层逻辑,分别对对侧的节点进行比较,然后利用递归对子节点比较,返回布尔值
- 迭代队列:
- 把左右节点放入队列中,每次取出两个节点进行逻辑比较,进行返回,然后把对侧节点按照对应顺序放入队列中
- 迭代栈:
- 和队列逻辑相同
代码:
/**
* 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 compare(root.left,root.right)
};
const compare = (left,right) => {
if (!left&&right) return false
else if (left&&!right) return false
else if (!left&&!right) return true
else if (left.val!== right.val) return false
let outside = compare(left.left,right.right)
let inside = compare(left.right,right.left)
let res = outside&&inside
return res
}
// 迭代队列:
var isSymmetric = function(root) {
if (!root) return true
const queue = [root.left,root.right]
while (queue.length) {
const left = queue.shift(),right = queue.shift()
if (!left&&!right){
continue
}
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)
}
return true
};
// 迭代栈:
var isSymmetric = function(root) {
if (!root) return true
const stack = [root.left,root.right]
while (stack.length) {
const left = stack.pop(),right = stack.pop()
if (!left&&!right){
continue
}
if (!left||!right||left.val!==right.val){
return false
}
stack.push(left.left)
stack.push(right.right)
stack.push(left.right)
stack.push(right.left)
}
return true
};
总结:
不难,是对二叉树理解的巩固
Day15总结
今天的内容很多,实际上我是分两次写完的,27号在高铁写完了层序遍历的内容,去深圳以后找房子准备入职工作做了好几天,今天2号全部安顿下来,其实30号1号也有时间写题,但是一旦脱离了学习状态后,再找回这种状态是一件很痛苦的事,总是喜欢拖延,明天就要入职了,有点紧张,说实话落下的内容已经太多,想要一次性补完不太现实,打算以每天写两天的题目来追赶进度,10天应该能追上,加油。