跟着代码随想录练算法——二叉树
- [144. 二叉树的前序遍历](https://leetcode.cn/problems/binary-tree-preorder-traversal/)
- [145. 二叉树的后序遍历](https://leetcode.cn/problems/binary-tree-postorder-traversal/)
- [94. 二叉树的中序遍历](https://leetcode.cn/problems/binary-tree-inorder-traversal/)
- [102. 二叉树的层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/)
- [107. 二叉树的层序遍历 II](https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/)
- [199. 二叉树的右视图](https://leetcode.cn/problems/binary-tree-right-side-view/)
- [637. 二叉树的层平均值](https://leetcode.cn/problems/average-of-levels-in-binary-tree/)
- [429. N 叉树的层序遍历](https://leetcode.cn/problems/n-ary-tree-level-order-traversal/)
- [589. N 叉树的前序遍历](https://leetcode.cn/problems/n-ary-tree-preorder-traversal/)
- [590. N 叉树的后序遍历](https://leetcode.cn/problems/n-ary-tree-postorder-traversal/)
- [515. 在每个树行中找最大值](https://leetcode.cn/problems/find-largest-value-in-each-tree-row/)
- [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/)
- [117. 填充每个节点的下一个右侧节点指针 II](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/)
- [104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/)
- [111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/)
- [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/)
- [101. 对称二叉树](https://leetcode.cn/problems/symmetric-tree/)
- [559. N 叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-n-ary-tree/)
- [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/)
- [110. 平衡二叉树](https://leetcode.cn/problems/balanced-binary-tree/)
- [257. 二叉树的所有路径](https://leetcode.cn/problems/binary-tree-paths/)
- [100. 相同的树](https://leetcode.cn/problems/same-tree/)
- [572. 另一棵树的子树](https://leetcode.cn/problems/subtree-of-another-tree/)
- [404. 左叶子之和](https://leetcode.cn/problems/sum-of-left-leaves/)
- [513. 找树左下角的值](https://leetcode.cn/problems/find-bottom-left-tree-value/)
- [112. 路径总和](https://leetcode.cn/problems/path-sum/)
- [113. 路径总和 II](https://leetcode.cn/problems/path-sum-ii/)
递归遍历
144. 二叉树的前序遍历
/**
* 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 preorderTraversal = function(root) {
let ans = []
var dfs = function(node){
if(node === null) return
ans.push(node.val)
dfs(node.left)
dfs(node.right)
}
dfs(root)
return ans
};
145. 二叉树的后序遍历
var postorderTraversal = function(root) {
let ans = []
var dfs = function (node){
if(node === null) return
dfs(node.left)
dfs(node.right)
ans.push(node.val)
}
dfs(root)
return ans
};
94. 二叉树的中序遍历
var inorderTraversal = function(root) {
let ans = []
var dfs = function(node){
if(node === null) return
dfs(node.left)
ans.push(node.val)
dfs(node.right)
}
dfs(root)
return ans
};
非递归(迭代)遍历
前序
- 先将根节点入栈
- 当栈不为空时,取出栈顶,访问栈顶
- 将栈顶节点右孩子入栈,左孩子入栈,因为这样之后弹栈的顺序就先是左孩子再是右孩子。
- 最后返回访问结果
var preorderTraversal = function(root) {
let ans = []
if(root === null) return ans
let stack = [root]
while(stack.length){
let top = stack.pop()
ans.push(top.val)
if(top.right) stack.push(top.right)
if(top.left) stack.push(top.left)
}
return ans
};
中序
先一路向左,将左节点入栈
当没有左节点时,弹栈访问,然后将栈顶右节点入栈
这里使用cur指针来访问节点
var inorderTraversal = function(root) {
let ans = []
if(root == null) return ans
let stack = []
let cur = root
while(stack.length || cur != null){
if(cur !== null){
stack.push(cur)
cur = cur.left
}else{
let top = stack.pop()
ans.push(top.val)
cur = top.right
}
}
return ans
};
后序
调整前序遍历左右节点的入栈顺序可以得到 前右左 的访问顺序,再将结果反转一下即可
var postorderTraversal = function(root) {
let ans = []
if(root == null) return ans
let stack = [root]
while(stack.length){
let top = stack.pop()
ans.push(top.val)
if(top.left) stack.push(top.left)
if(top.right) stack.push(top.right)
}
return ans.reverse()
};
层序遍历
102. 二叉树的层序遍历
- 由于要将每一层的遍历放在一个单独的数组中
- 于是使用内层循环去遍历每一层
- 每一层的结果放在each中,一层遍历结束之后放在ans中
/**
* 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) {
let ans = []
if(root === null) return ans
let queue = [root]
let len = 1
while(queue.length){
let each = []
let t = len
len = 0
while(t --){
let front = queue.shift()
each.push(front.val)
if(front.left){
len ++
queue.push(front.left)
}
if(front.right){
len ++
queue.push(front.right)
}
}
ans.push(each)
}
return ans
};
107. 二叉树的层序遍历 II
这题要求的层序是自下而上,只需要将上一题的ans逆序
/**
* 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) {
let ans = []
if(root === null) return ans
let queue = [root]
let len = 1
while(queue.length){
let each = []
let t = len
len = 0
while(t --){
let front = queue.shift()
each.push(front.val)
if(front.left){
len ++
queue.push(front.left)
}
if(front.right){
len ++
queue.push(front.right)
}
}
ans.push(each)
}
return ans.reverse()
};
199. 二叉树的右视图
和前面两题类似,记录下每层的结果each,最终只将each的最后一个元素拿出放到ans中即可
/**
* 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) {
let ans = []
if(root === null) return ans
let queue = [root]
let len = 1
while(queue.length){
let each = []
let t = len
len = 0
while(t --){
let front = queue.shift()
each.push(front.val)
if(front.left){
len ++
queue.push(front.left)
}
if(front.right){
len ++
queue.push(front.right)
}
}
ans.push(each[each.length - 1])
}
return ans
};
637. 二叉树的层平均值
这次不用each记录每一层的val,使用sum记录每一层的总和,再用count记录每层元素个数,每一层结束之后计算平均值放入ans
var averageOfLevels = function(root) {
let ans = []
if(root === null) return ans
let queue = [root]
let len = 1
while(queue.length){
let sum = 0
let count = len
let t = len
len = 0
while(t --){
let front = queue.shift()
sum += front.val
if(front.left){
len ++
queue.push(front.left)
}
if(front.right){
len ++
queue.push(front.right)
}
}
ans.push(sum/count)
}
return ans
};
429. N 叉树的层序遍历
内层循环需要判断children,遍历孩子然后放入queue
/**
* // Definition for a Node.
* function Node(val,children) {
* this.val = val;
* this.children = children;
* };
*/
/**
* @param {Node|null} root
* @return {number[][]}
*/
var levelOrder = function(root) {
let ans = []
if(root == null) return ans
let queue = [root]
let len = 1
while(queue.length){
let each = []
let t = len
len = 0
while(t--){
let front = queue.shift()
each.push(front.val)
if(front.children){
for(let i = 0; i < front.children.length; i ++){
queue.push(front.children[i])
len ++
}
}
}
ans.push(each)
}
return ans
};
589. N 叉树的前序遍历
/**
* // Definition for a Node.
* function Node(val, children) {
* this.val = val;
* this.children = children;
* };
*/
/**
* @param {Node|null} root
* @return {number[]}
*/
var preorder = function(root) {
let ans = []
function dfs(node){
if(node == null) return
ans.push(node.val)
if(node.children){
for(let i = 0; i < node.children.length; i++){
dfs(node.children[i])
}
}
}
dfs(root)
return ans
};
590. N 叉树的后序遍历
/**
* // Definition for a Node.
* function Node(val,children) {
* this.val = val;
* this.children = children;
* };
*/
/**
* @param {Node|null} root
* @return {number[]}
*/
var postorder = function(root) {
let ans = []
function dfs(node){
if(!node) return
if(node.children){
for(let i = 0; i < node.children.length; i++){
dfs(node.children[i])
}
}
ans.push(node.val)
}
dfs(root)
return ans
};
515. 在每个树行中找最大值
max 来记录每层的最大值,当一层遍历结束之后,将最大值放入ans数组
/**
* 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) {
let ans = []
if(root === null) return ans
let queue = [root]
let len = 1
while(queue.length){
let max = null
let t = len
len = 0
while(t --){
let front = queue.shift()
if(max === null) max = front.val
else{
if(front.val > max) max = front.val
}
if(front.left){
queue.push(front.left)
len ++
}
if(front.right){
queue.push(front.right)
len ++
}
}
ans.push(max)
}
return ans
};
116. 填充每个节点的下一个右侧节点指针
题目的意思是将每一层的节点串起来
每层的each数组收集当前层的节点,收集结束之后,再串起来
/**
* // 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) {
if(root === null) return root
let queue = [root]
let len = 1
while(queue.length){
let each = []
let t = len
len = 0
while(t --){
let front = queue.shift()
each.push(front)
if(front.left){
len ++
queue.push(front.left)
}
if(front.right){
len ++
queue.push(front.right)
}
}
let node = each[0]
for(let i = 1; i < each.length; i++){
node.next = each[i]
node = each[i]
}
}
return root
};
117. 填充每个节点的下一个右侧节点指针 II
和116题代码一样,但是我提交的时候总是报错,不知道为什么
throw new TypeError(_serialize_(ret) + " is not valid value for the expected return type Node "
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) {
let max = 0
function dfs(node, depth){
// console.log(node.val, depth)
if(!node) return
if((node.left == null && node.right == null)){
max = Math.max(max,depth)
}
if(node.left) dfs(node.left, depth + 1)
if(node.right) dfs(node.right, depth + 1)
}
dfs(root, 1)
return max
};
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) {
let min = 0
function dfs(node, depth){
if(!node) return
if(!(node.left || node.right)){
if(min === 0) min = depth
else min = Math.min(depth, min)
return
}
if(node.left) dfs(node.left, depth + 1)
if(node.right) dfs(node.right, depth + 1)
}
dfs(root, 1)
return min
};
226. 翻转二叉树
翻转每个节点的左右孩子,一边遍历,一边翻转
/**
* 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 t = root.left
root.left = root.right
root.right = t
invertTree(root.left)
invertTree(root.right)
return root
};
101. 对称二叉树
- 确定递归函数参数:由于需要判断左右子树,所有传入的参数为左右子树
- 递归函数返回值和终止条件:
- false:两个子树不对称
- 当两个子树中一个为空一个不为空 return false
- 当两个子树的根节点val值不一样 return false
- 当左子树的左孩子和右子树的右孩子不对称或者左子树的右孩子和右子树的左孩子不对称时 return false
- true:两个子树对称
- 左子树和右子树同时为空 return true
- 当左子树的左孩子和右子树的右孩子对称并且左子树的右孩子和右子树的左孩子对称时 retrun true
- false:两个子树不对称
/**
* 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
function dfs(left, right){
if( !left && !right) return true
else if(!left || !right) return false
else if( left.val !== right.val) return false
let ans1 = dfs(left.left, right.right)
let ans2 = dfs(left.right, right.left)
if(ans1 && ans2) return true
else return false
}
return dfs(root.left, root.right)
};
559. N 叉树的最大深度
递归函数的返回值为当前最大深度,是所有孩子中的最大深度 + 1
/**
* // Definition for a Node.
* function Node(val,children) {
* this.val = val;
* this.children = children;
* };
*/
/**
* @param {Node|null} root
* @return {number}
*/
var maxDepth = function(root) {
function dfs(node){
if(!node) return 0
else if(!node.children) return 1
let max = dfs(node.children[0])
for(let i = 1; i < node.children.length; i++){
max = Math.max(max, dfs(node.children[i]))
}
return max + 1
}
return dfs(root)
};
222. 完全二叉树的节点个数
递归遍历计算
/**
* 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 countNodes = function(root) {
function dfs(node){
if(node == null) return 0
let leftNum = dfs(node.left)
let RightNum = dfs(node.right)
return leftNum + RightNum + 1
}
return dfs(root)
};
如果是满二叉树,则叶子结点个数为
2^n - 1
110. 平衡二叉树
深度: 根节点 => 该节点
高度:该节点 => 叶子结点
/**
* 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 isBalanced = function(root) {
function dfs(node){
if(node == null) return 0
let l = dfs(node.left)
if(l == -1) return -1
let r = dfs(node.right)
if(r == -1) return -1
if(Math.abs(l-r) > 1) return -1
return Math.max(l,r) + 1
}
return dfs(root) == -1 ? false : true
};
257. 二叉树的所有路径
/**
* 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 {string[]}
*/
var binaryTreePaths = function(root) {
let ans = []
let each = []
function dfs(node){
if(!node) return
if( !node.left && !node.right){
each.push(node.val)
ans.push(each.join('->'))
return
}
each.push(node.val)
if(node.left){
dfs(node.left)
each.pop()
}
if(node.right){
dfs(node.right)
each.pop()
}
}
dfs(root)
return ans
};
100. 相同的树
/**
* 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} p
* @param {TreeNode} q
* @return {boolean}
*/
var isSameTree = function(p, q) {
// p,q都是null
if( !p && !q) return true
else if( !p || !q) return false
else if( p.val != q.val) return false
let ans1 = isSameTree(p.left, q.left)
let ans2 = isSameTree(p.right, q.right)
return ans1&&ans2 ? true : false
};
572. 另一棵树的子树
- findRoot 来寻找root中与subRootval值一样的节点,然后作比较
- isSame判断传入的两颗二叉树是否相同 返回true或者false
/**
* 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
* @param {TreeNode} subRoot
* @return {boolean}
*/
var isSubtree = function(root, subRoot) {
let ans = false
function isSame(p, q){
if(!p && !q) return true
else if(!p || !q) return false
else if(p.val != q.val) return false
let ans1 = isSame(p.left, q.left)
let ans2 = isSame(p.right, q.right)
return ans1&&ans2 ? true : false
}
function findRoot(node){
if(!node) return
if(node.val == subRoot.val && !ans){
let res = isSame(node, subRoot)
if(res){
ans = true
return
}
}
if(root.left) findRoot(node.left)
if(root.right) findRoot(node.right)
}
findRoot(root)
return ans
};
404. 左叶子之和
递归遍历,如果当前节点有左节点并且左节点是叶子结点,则累加
/**
* 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 sumOfLeftLeaves = function(root) {
let sum = 0
function dfs(node){
if(!node) return
else if(node.left && !node.left.left && !node.left.right){
sum += node.left.val
}
dfs(node.left)
dfs(node.right)
}
dfs(root)
return sum
};
513. 找树左下角的值
返回层序遍历最后一层的结果的第一个节点值
/**
* 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 findBottomLeftValue = function(root) {
let ans = []
if(!root) return null
let queue = [root]
let len = 1
while(queue.length){
let each = []
let t = len
len = 0
while(t--){
let front = queue.shift()
each.push(front.val)
if(front.left){
len ++
queue.push(front.left)
}
if(front.right){
len ++
queue.push(front.right)
}
}
ans = each
}
return ans[0]
};
112. 路径总和
递归函数是否需要返回值?判定条件
- 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(113.路径总和ii)
- 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (236. 二叉树的最近公共祖先)
- 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
递归函数参数:node 当前节点 count 总的路径和减去当前经过的路径和
递归函数:
- 当遍历到叶子结点并且当前count=0 返回true
- 当遍历到叶子结点并且当前 count != 0 返回false
- 如果有左子树并且左子树遍历返回值为true 则返回true
- 右子树类似
- 以上情况都不满足 返回false
/**
* 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
* @param {number} targetSum
* @return {boolean}
*/
var hasPathSum = function(root, targetSum) {
if(!root) return false
function dfs(node, count){
if( !node.left && !node.right && count == 0){
return true
}else if( !node.left && !node.right && count != 0){
return false
}
if(node.left && dfs(node.left, count - node.left.val)) return true
if(node.right && dfs(node.right, count - node.right.val)) return true
return false
}
return dfs(root, targetSum - root.val)
};
113. 路径总和 II
这次的递归函数不需要设置返回值,每一次遍历到叶子节点将满足的路径直接记录在ans数组中即可
记得记录当前路径的each数组需要回溯操作
/**
* 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
* @param {number} targetSum
* @return {number[][]}
*/
var pathSum = function(root, targetSum) {
let ans = []
let each = []
if(!root) return ans
function traversal(node, count){
if( !node.left && !node.right && count == 0){
ans.push([...each])
return
}else if( !node.left && !node.right && count != 0){
return
}
if(node.left){
each.push(node.left.val)
traversal(node.left, count - node.left.val)
each.pop()
}
if(node.right){
each.push(node.right.val)
traversal(node.right, count - node.right.val)
each.pop()
}
}
each.push(root.val)
traversal(root, targetSum - root.val)
return ans
};