(声明:所有题目都是leetcode上非会员题目)
树的定义
在计算机科学中,树(英语:tree)是一种抽象数据类型(ADT)或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由n(n>0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
- 每个节点都只有有限个子节点或无子节点;
- 没有父节点的节点称为根节点;
- 每一个非根节点有且只有一个父节点;
- 除了根节点外,每个子节点可以分为多个不相交的子树;
- 树里面没有环路(cycle)

二叉树
在计算机科学中,二叉树(英语:Binary tree)是每个节点最多只有两个分支(即不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒。
一棵深度为k,且有2^k-1个结点的二叉树,称为满二叉树。这种树的特点是每一层上的结点数都是最大结点数。而在一棵二叉树中,除最后一层外,若其余层都是满的,并且或者最后一层是满的,或者是在右边缺少连续若干结点,则此二叉树为完全二叉树。具有n个结点的完全二叉树的深度为Math.floor(log2n)+1。深度为k的完全二叉树,至少有2k-1个叶子结点,至多有2k-1个结点。
与普通树不同,普通树的节点个数至少为1,而二叉树的节点个数可以为0;普通树节点的最大分支度没有限制,而二叉树节点的最大分支度为2;普通树的节点无左、右次序之分,而二叉树的节点有左、右次序之分。
二叉查找树
二叉查找树(英语:Binary Search Tree),也称为二叉搜索树、有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树:
- 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
- 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
- 任意节点的左、右子树也分别为二叉查找树;
- 没有键值相等的节点。
二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。为O(logn)
中序遍历二叉查找树可得到一个节点值的有序序列,一个无序序列可以透过建构一棵二叉查找树变成一个有序序列,建构树的过程即为对无序序列进行查找的过程。每次插入的新的结点都是二叉查找树上新的叶子结点,在进行插入操作时,不必移动其它结点,只需改动某个结点的指针,由空变为非空即可。搜索、插入、删除的复杂度等于树高,p平均时间复杂度O(logn),最坏O(n)。
虽然二叉查找树的最坏效率是O(n),但它支持动态查询,且有很多改进版的二叉查找树可以使树高为O(logn),从而将最坏效率降至O(logn),如AVL树、红黑树等
本文将不断收录自己在解决leetcode上算法问题时,遇到的和树这种数据结构相关的问题
树相关问题技巧
- 层序遍历过程中,用
index来维护节点索引,一个节点索引是index,那他的左孩子索引是index * 2,右孩子索引是index * 2 + 1 - 树形问题很多都可以用递归解决
- 树形问题总是涉及到BFS或者DFS过程
Leetcode上树相关的问题
leetcode 94, 144, 145. 二叉树的前中后序遍历
题目地址:二叉树的前序遍历 二叉树的中序遍历 二叉树的后序遍历
关于这三个二叉树最基本的问题,我在另一篇专栏里有详细给出解法,这里不再列出,可以参考 二叉树前中后序遍历非递归实现(JavaScript)
leetcode 98. 验证二叉搜索树
题目地址:验证二叉搜索树

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isValidBST = function(root, min = -Infinity, max = Infinity) {
if (!root) return true;
if (root.val <= min || root.val >= max) return false;
return isValidBST(root.left, min, root.val) && isValidBST(root.right, root.val, max);
};
leetcode 100. 相同的树
题目地址:相同的树

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} p
* @param {TreeNode} q
* @return {boolean}
*/
var isSameTree = function(p, q) {
if (!p && !q) {
return true
}
if ((!p && q) || (p && !q)) {
return false
}
if (p && q) {
if (p.val === q.val) {
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right)
} else {
return false
}
}
};
leetcode 101. 对称二叉树
题目地址:对称二叉树

/**
* 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) {
function isMirror (node1, node2) {
if (node1 == null && node2 == null) return true;
if (node1 == null || node2 == null) return false;
return (node1.val == node2.val) && isMirror(node1.right, node2.left) && isMirror(node1.left, node2.right)
}
return isMirror(root, root)
};
leetcode 102. 二叉树的层次遍历
题目地址:二叉树的层次遍历
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrder = function(root) {
let res = []
let queue = []
if (root) {
let level = 0
queue.push({ node: root, level })
while (queue.length) {
const item = queue.shift()
const node = item.node
let level = item.level
if (level === res.length) {
res.push([])
}
res[level].push(node.val)
node.left && queue.push({ node: node.left, level: level + 1 })
node.right && queue.push({ node: node.right, level: level + 1 })
}
}
return res
};
leetcode 103. 二叉树的锯齿形层次遍历
题目地址:二叉树的锯齿形层次遍历

BFS,level维护层级
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var zigzagLevelOrder = function(root) {
const res = []
if (root) {
const queue = [root]
let level = 0
while (queue.length) {
const len = queue.length
const arr = []
if (level % 2) {
for (let i = 0; i < len; i++) {
const node = queue.shift()
node.left && queue.push(node.left)
node.right && queue.push(node.right)
arr.unshift(node.val)
}
} else {
for (let i = 0; i < len; i++) {
const node = queue.shift()
node.left && queue.push(node.left)
node.right && queue.push(node.right)
arr.push(node.val)
}
}
res.push(arr)
level ++
}
}
return res
};
leetcode 104. 二叉树的最大深度
题目地址:二叉树的最大深度

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var maxDepth = function(root) {
if (root === null) {
return 0
}
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1
};
leetcode 105. 从前序与中序遍历序列构造二叉树
题目地址:从前序与中序遍历序列构造二叉树

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {number[]} preorder
* @param {number[]} inorder
* @return {TreeNode}
*/
var buildTree = function(preorder, inorder) {
if (!preorder.length || !inorder.length) {
return null
}
// 根节点
const root = new TreeNode(preorder[0])
const index = inorder.indexOf(root.val);
// 递归找到每个节点
root.left = buildTree(preorder.slice(1,index+1),inorder.slice(0,index))
root.right = buildTree(preorder.slice(index+1), inorder.slice(index + 1))
return root
};
leetcode 106. 从中序与后序遍历序列构造二叉树
题目地址:从中序与后序遍历序列构造二叉树

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {number[]} inorder
* @param {number[]} postorder
* @return {TreeNode}
*/
var buildTree = function(inorder, postorder) {
if (!inorder.length || !postorder.length) {
return null
}
const root = new TreeNode(postorder[postorder.length - 1])
const i = inorder.indexOf(root.val)
root.left = buildTree(inorder.slice(0, i), postorder.slice(0, i))
root.right = buildTree(inorder.slice(i + 1), postorder.slice(i, postorder.length - 1))
return root
};
leetcode 107. 二叉树的层次遍历 II
题目地址:二叉树的层次遍历II

解法一:DFS
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrderBottom = function(root) {
let res = []
let queue = []
if (root) {
let level = 0
queue.push({ node: root, level })
while (queue.length) {
const item = queue.shift()
const node = item.node
const level = item.level
if (level === res.length) {
res.unshift([])
}
res[0].push(node.val)
node.left && queue.push({ node: node.left, level: level + 1 })
node.right && queue.push({ node: node.right, level: level + 1 })
}
}
return res
};
解法二:BFS
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrderBottom = function(root) {
const res = []
if (root) {
const queue = [root]
while (queue.length) {
const len = queue.length
const temp = []
for (let i = 0; i < len; i++) {
const node = queue.shift()
temp.push(node.val)
node.left && queue.push(node.left)
node.right && queue.push(node.right)
}
res.unshift(temp)
}
}
return res
};
leetcode 108. 将有序数组转换为二叉搜索树
题目地址:将有序数组转换为二叉搜索树

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {number[]} nums
* @return {TreeNode}
*/
var sortedArrayToBST = function (nums) {
if (nums.length == 0) return null;
let cen = Math.floor(nums.length / 2)
let node = new TreeNode(nums[cen])
node.left = sortedArrayToBST(nums.slice(0, cen))
node.right = sortedArrayToBST(nums.slice(cen + 1))
return node;
};
leetcode 110. 平衡二叉树
题目地址:平衡二叉树

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isBalanced = function(root) {
// 遍历到底还没有发现高度差超过 1 的左右子树,那么这个子树肯定符合平衡二叉树的规范
if (!root) {
return true
}
// 判断左右子树的高度差,如果超过 1 那么立即返回 false
if (Math.abs(getHeight(root.left) - getHeight(root.right)) > 1) {
return false
}
// 分别递归左右子树
return isBalanced(root.left) && isBalanced(root.right)
// 获取某个子树的高度
function getHeight (root) {
if (!root) {
return 0
}
return Math.max(getHeight(root.left), getHeight(root.right)) + 1
}
};
leetcode 111. 二叉树的最小深度
题目地址:二叉树的最小深度

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var minDepth = function(root) {
if (!root) {
return 0
}
if (root.left === null && root.right === null) {
return 1
}
if (root.left && !root.right) {
return minDepth(root.left) + 1
}
if (!root.left && root.right) {
return minDepth(root.right) + 1
}
return Math.min(minDepth(root.left), minDepth(root.right)) + 1
};
leetcode 112. 路径总和
题目地址:路径总和

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {number} sum
* @return {boolean}
*/
var hasPathSum = function(root, sum) {
if (!root) {
return false
}
if (!root.left && !root.right) {
return root.val === sum
}
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val)
};
leetcode 113. 路径总和 II
题目地址:路径总和 II

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {number} sum
* @return {number[][]}
*/
var pathSum = function(root, sum) {
const result = []
const digui = function(node, route, localSum){
if(!node) return
route.push(node.val)
if(!node.left && !node.right && node.val + localSum === sum){
result.push(route.slice())
}else{
if(node.left) digui(node.left, route.slice(), localSum + node.val)
if(node.right) digui(node.right, route.slice(), localSum + node.val)
}
}
digui(root, [], 0)
return result
};
leetcode 114. 二叉树展开为链表
题目地址:二叉树展开为链表

解法一:先序遍历
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {void} Do not return anything, modify root in-place instead.
*/
var flatten = function (root) {
if (!root) {
return null
}
let temp = new TreeNode(null)
temp.right = root
const stack = [root]
let prev = temp
while (stack.length > 0) {
root = stack.pop()
prev.right = root
prev.left = null
root.right && stack.push(root.right)
root.left && stack.push(root.left)
prev = root
}
return temp.right
}
解法二:
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {void} Do not return anything, modify root in-place instead.
*/
var flatten = function (root) {
let node = root
while (node) {
if (node.left) {
// 找到当前节点左节点的最右子节点
let temp = node.left
while (temp.right) {
temp = temp.right
}
// 最右子节点的有节点指向为当前节点右节点
temp.right = node.right
// 把当前节点右节点指向左节点
node.right = node.left
// 左节点为空
node.left = null
}
node = node.right
}
return root
}
leetcode 129. 求根到叶子节点数字之和
题目地址:求根到叶子节点数字之和

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var sumNumbers = function(root) {
var binaryTreePaths = function(root) {
const res = []
if (!root) {
return res
}
if (!root.left && !root.right ) {
res.push(root.val.toString())
return res
}
const leftPath = binaryTreePaths(root.left)
for (let i = 0; i < leftPath.length; i++) {
res.push(root.val.toString() + leftPath[i])
}
const rightPath = binaryTreePaths(root.right)
for (let i = 0; i < rightPath.length; i++) {
res.push(root.val.toString() + rightPath[i])
}
return res
};
const arr = binaryTreePaths(root)
let sum = 0
if (arr .length) {
arr.forEach(item => {
sum += parseInt(item)
})
}
return sum
};
leetcode 173. 二叉搜索树迭代器
题目地址:二叉搜索树迭代器

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
const inorderTraversal = function(root) {
const res = [], stack = []
let node = root;
while (stack.length > 0 || node !== null) {
// 这里用当前节点node是否存在,简化代码,
if (node) {
stack.push(node);
node = node.left
} else {
node = stack.pop();
res.push(node.val);
node = node.right;
}
}
return res;
};
/**
* @param {TreeNode} root
*/
var BSTIterator = function(root) {
this.res = inorderTraversal(root)
this.cur = 0
};
/**
* @return the next smallest number
* @return {number}
*/
BSTIterator.prototype.next = function() {
const index = this.cur
this.cur ++
return this.res[index]
};
/**
* @return whether we have a next smallest number
* @return {boolean}
*/
BSTIterator.prototype.hasNext = function() {
return this.cur < this.res.length
};
/**
* Your BSTIterator object will be instantiated and called as such:
* var obj = new BSTIterator(root)
* var param_1 = obj.next()
* var param_2 = obj.hasNext()
*/
leetcode 199. 二叉树的右视图
题目地址:二叉树的右视图

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
// BFS
var rightSideView = function(root) {
if (!root) {
return []
}
const nums = [root]
const res = []
let right
while (nums.length) {
let len = nums.length
for (let i = 0; i < len; i++) {
let node = nums.shift()
right = node.val
node.left && nums.push(node.left)
node.right && nums.push(node.right)
}
res.push(right)
}
return res
};
leetcode 222. 完全二叉树的节点个数
题目地址:完全二叉树的节点个数

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var countNodes = function(root) {
if (!root) {
return 0
}
let left_height = 0
let left_node = root
let right_height = 0
let right_node = root
while(left_node) {
left_node = left_node.left
left_height += 1
}
while (right_node) {
right_node = right_node.right
right_height += 1
}
if (left_height === right_height) {
return Math.pow(2, left_height) - 1
}
return 1 + countNodes(root.left) + countNodes(root.right)
};
leetcode 226. 翻转二叉树
题目地址:翻转二叉树

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
if (!root) {
return null
}
[root.left, root.right] = [invertTree(root.right), invertTree(root.left)]
return root
};
leetcode 230. 二叉搜索树中第K小的元素
题目地址:二叉搜索树中第K小的元素

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {number} k
* @return {number}
*/
// 二叉搜索树中序遍历,得到的是从小到大排列
var kthSmallest = function(root, k) {
let res = [];
function lnr(node){
if(node && res.length<k){
lnr(node.left);
res.push(node.val);
lnr(node.right);
}
}
lnr(root);
return res[k-1];
};
leetcode 235. 二叉搜索树的最近公共祖先
题目地址:二叉搜索树的最近公共祖先

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
var lowestCommonAncestor = function(root, p, q) {
if (p.val < root.val && q.val < root.val) {
return lowestCommonAncestor(root.left, p, q)
} else if (p.val > root.val && q.val > root.val) {
return lowestCommonAncestor(root.right, p, q)
} else {
return root
}
};
leetcode 236. 二叉树的最近公共祖先
题目地址:二叉树的最近公共祖先

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
var lowestCommonAncestor = function(root, p, q) {
if(root == null || root == p || root == q){
return root;
}
let left = lowestCommonAncestor(root.left,p,q);
let right = lowestCommonAncestor(root.right,p,q);
// p,q在root的左右子树
if(left != null && right != null){
return root;
}
// 只找到一个说明,p,q之一就是最近公共结点,另一个是该节点子节点
return left != null ? left : right;
};
leetcode 257. 二叉树的所有路径
题目地址:二叉树的所有路径

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {string[]}
*/
var binaryTreePaths = function(root) {
const res = []
if (!root) {
return res
}
if (!root.left && !root.right ) {
res.push(root.val.toString())
return res
}
const leftPath = binaryTreePaths(root.left)
for (let i = 0; i < leftPath.length; i++) {
res.push(root.val.toString() + '->' + leftPath[i])
}
const rightPath = binaryTreePaths(root.right)
for (let i = 0; i < rightPath.length; i++) {
res.push(root.val.toString() + '->' + rightPath[i])
}
return res
};
leetcode 404. 左叶子之和
题目地址:左叶子之和

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var sumOfLeftLeaves = function(root) {
if(!root) return 0;
let sum = 0;
let fn = (curNode) => {
if(curNode.left && (!curNode.left.left && !curNode.left.right)){
sum += curNode.left.val;
}
if(curNode.left){
fn(curNode.left)
}
if(curNode.right){
fn(curNode.right)
}
}
fn(root)
return sum;
};
leetcode 450. 删除二叉搜索树中的节点
题目地址:删除二叉搜索树中的节点

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {number} key
* @return {TreeNode}
*/
var deleteNode = function(root, key) {
if(root == null){
return root;
}
if(key == root.val){
// 如果该节点的左子树为空,返回该节点的右子树
if(root.left == null){
return root.right;
} else if(root.right == null){
return root.left;
} else {
let node = root.right;
while(node.left != null){
node = node.left;
}
node.left = root.left;
return root.right;
}
// key 比root大,则从右子树中删除 key 节点
} else if(key > root.val) {
root.right = deleteNode(root.right,key);
} else {
root.left = deleteNode(root.left,key);
}
return root;
}
leetcode 501. 二叉搜索树中的众数
题目地址:二叉搜索树中的众数

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var findMode = function(root) {
let res = [], maxcount = 0, prev = null, count = 0
function binarySearch (root) {
if (!root) {
return
}
binarySearch(root.left)
if (prev === root.val) {
count ++
} else {
count = 1
}
if (maxcount === count) {
res.push(root.val)
} else if (maxcount < count) {
res = [root.val]
maxcount = count
}
prev = root.val
binarySearch(root.right)
}
binarySearch(root)
return res
};
leetcode 530. 二叉搜索树的最小绝对差
题目地址:二叉搜索树的最小绝对差

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var getMinimumDifference = function(root) {
// 中序遍历,对于二叉搜索树就是从小到大排序(非递归)
const res = [], stack = []
let node = root;
while (stack.length > 0 || node !== null) {
// 这里用当前节点node是否存在,简化代码,
if (node) {
stack.push(node);
node = node.left
} else {
node = stack.pop();
res.push(node.val);
node = node.right;
}
}
const len = res.length
let min = Infinity
// 遍历,找到最小绝对差
for (let i = 0; i < len - 1; i ++) {
min = Math.min(min, Math.abs(res[i] - res[i + 1]))
}
return min
};
leetcode 543. 二叉树的直径
题目地址:二叉树的直径

这个问题本质是求一棵树左右子树的高度和
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var diameterOfBinaryTree = function(root) {
let res = 0
function getHeight (root) {
if (!root) {
return 0
}
// 左子树深度
const left = root.left ? getHeight(root.left) + 1 : 0
// 右子树深度
const right = root.right ? getHeight(root.right) + 1 : 0
res = Math.max(left + right, res)
return Math.max(left, right)
}
getHeight(root)
return res
};
leetcode 559. N叉树的最大深度
题目地址:N叉树的最大深度

/**
* // Definition for a Node.
* function Node(val,children) {
* this.val = val;
* this.children = children;
* };
*/
/**
* @param {Node} root
* @return {number}
*/
var maxDepth = function(root) {
if (!root) {
return 0
}
let stack = [{ node: root, level: 1 }]
let max = 1
while (stack.length) {
const temp = stack.shift()
const node = temp.node
const level = temp.level
max = Math.max(level, max)
if (node.children && node.children.length) {
for (let i = 0; i < node.children.length; i++) {
stack.push({node: node.children[i], level: level + 1})
}
}
}
return max
};
解法二: 递归
var maxDepth = function(root) {
if(!root) {
return 0
}
let depth = 0
if(root.children){
root.children.forEach(item=>{
let max = maxDepth(item)
depth = Math.max(max, depth)
})
}
return depth + 1
};
leetcode 563. 二叉树的坡度
题目地址:二叉树的坡度

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var findTilt = function(root) {
let sum = 0
function getSum (root) {
if (!root) {
return 0
}
const leftSum = getSum(root.left)
const rightSum = getSum(root.right)
sum += Math.abs(leftSum - rightSum)
return leftSum + rightSum + root.val
}
getSum(root)
return sum
};
leetcode 572. 另一个树的子树
题目地址:另一个树的子树

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} s
* @param {TreeNode} t
* @return {boolean}
*/
// 遍历树s,判断s是否包含t
var isSubtree = function(s, t) {
if (!s) return false;
if (_isSubtree(s, t)) return true;
return isSubtree(s.left, t) || isSubtree(s.right, t);
};
// s是否和t是相同的树
function _isSubtree(s, t) {
if (!s && !t) return true;
if (!s || !t) return false;
if (s.val != t.val) return false;
return _isSubtree(s.left, t.left) && _isSubtree(s.right, t.right);
}
leetcode 589. N叉树的前序遍历
题目地址:N叉树的前序遍历

/**
* // Definition for a Node.
* function Node(val, children) {
* this.val = val;
* this.children = children;
* };
*/
/**
* @param {Node} root
* @return {number[]}
*/
var preorder = function(root) {
const res = []
if (root) {
const temp = [root]
while (temp.length) {
const node = temp.pop()
res.push(node.val)
for (let i = node.children.length - 1; i >= 0 ; i--) {
temp.push(node.children[i])
}
}
}
return res
};
leetcode 590. N叉树的后序遍历
题目地址:N叉树的后序遍历

解法一:递归
/**
* // Definition for a Node.
* function Node(val,children) {
* this.val = val;
* this.children = children;
* };
*/
/**
* @param {Node} root
* @return {number[]}
*/
// 递归
var postorder = function(root) {
function _postorder (root) {
if (!root) {
return
}
const children = root.children
const len = children.length
for (let i = 0; i < len; i++) {
_postorder(children[i])
}
res.push(root.val)
}
const res = []
root && _postorder(root)
return res
};
解法二:迭代
/**
* // Definition for a Node.
* function Node(val,children) {
* this.val = val;
* this.children = children;
* };
*/
/**
* @param {Node} root
* @return {number[]}
*/
// 迭代
var postorder = function(root) {
const res = []
if (root) {
const res = [], temp = [root]
while (temp.length) {
const node = temp.pop()
for (let i = 0; i < node.children.length; i++) {
temp.push(node.children[i])
}
res.unshift(node.val)
}
}
return res
};
leetcode 617. 合并二叉树
题目地址:合并二叉树

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} t1
* @param {TreeNode} t2
* @return {TreeNode}
*/
var mergeTrees = function(t1, t2) {
if(!t1){
return t2
}else if(!t2){
return t1
}else{
t2.val = t1.val + t2.val
t2.left = mergeTrees(t1.left, t2.left)
t2.right = mergeTrees(t1.right, t2.right)
return t2
}
};
leetcode 637. 二叉树的层平均值
题目地址:二叉树的层平均值

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var averageOfLevels = function(root) {
let res = []
if (root) {
let queue = [root]
while (queue.length) {
const len = queue.length
let sum = 0
for (let i = 0; i < len; i++) {
const node = queue.shift()
sum += node.val
node.left && queue.push(node.left)
node.right && queue.push(node.right)
}
res.push(sum / len)
}
}
return res
};
解法二:深度优先搜索(DFS)
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
var averageOfLevels = function(root) {
let temp = []
let res = []
let queue = []
if (root) {
let level = 0
queue.push({ node: root, level })
while (queue.length) {
const item = queue.shift()
const node = item.node
const level = item.level
if (level === temp.length) {
temp.push([])
}
temp[level].push(node.val)
node.left && queue.push({ node: node.left, level: level + 1 })
node.right && queue.push({ node: node.right, level: level + 1 })
}
}
if (temp.length) {
for (let i = 0; i < temp.length; i++) {
const arr = temp[i]
const sum = arr.reduce((a, b) => a + b)
const average = sum / arr.length
res.push(average)
}
}
return res
};
leetcode 662. 二叉树最大宽度
题目地址:二叉树最大宽度

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var widthOfBinaryTree = function(root) {
if (!root) {
return 0
}
const queue = [{ node: root, index: 1 }]
let max = 1
while (queue.length) {
const len = queue.length
// 这一层的长度为1不需要计算宽度
if (len > 1) {
const start = queue[0].index
const end = queue[len - 1].index
const width = end - start + 1
max = Math.max(max, width)
}
for (let i = 0; i < len; i++) {
const temp = queue.shift()
const node = temp.node
const index = temp.index
// 层序遍历过程中,用index来维护节点索引,一个节点索引是index,那他的左孩子索引是index * 2,右孩子索引是index * 2 +1
node.left && queue.push({ node: node.left, index: index * 2 })
node.right && queue.push({ node: node.right, index: index * 2 + 1 })
}
}
return max
};
leetcode 894. 所有可能的满二叉树
题目地址:所有可能的满二叉树

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {number} N
* @return {TreeNode[]}
*/
var allPossibleFBT = function(N) {
const map = new Map()
// 数据缓存,map中已有则不再重复计算
if (!map.has(N)) {
const ans = []
if (N === 1) {
ans.push(new TreeNode(0))
// 只有N为奇数的时候,才满足构成满二叉树
} else if (N % 2 === 1) {
for (let i = 0; i < N; i++) {
const j = N - i - 1
// 对于每一个i作为构建一个树的做节点的节点个树
let leftNodes = allPossibleFBT(i)
// 构成右节点的节点个树是N - j - 1,减去的1是节点本身
let rightNodes = allPossibleFBT(j)
// 循环枚举所有可能
leftNodes.forEach(left => {
rightNodes.forEach(right => {
// 根节点
const node = new TreeNode(0)
node.left = left
node.right = right
ans.push(node)
})
})
}
}
map.set(N, ans)
}
return map.get(N)
};
leetcode 938. 二叉搜索树的范围和
题目地址:二叉搜索树的范围和

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {number} L
* @param {number} R
* @return {number}
*/
var rangeSumBST = function(root, L, R) {
const stack = []
let node = root;
let sum = 0
while (stack.length > 0 || node !== null) {
if (node) {
stack.push(node);
node = node.left
} else {
node = stack.pop();
if (node.val >= L && node.val <= R) {
sum += node.val
}
node = node.right;
}
}
return sum
};
leetcode 958. 二叉树的完全性检验
题目地址:二叉树的完全性检验

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isCompleteTree = function(root) {
if (!root) {
return true
}
const queue = [{ node: root, index: 1 }]
let count = 0
while (queue.length) {
const temp = queue.shift()
const node = temp.node
const index = temp.index
// 用来判断索引位置节点是否存在,如果index !== ++count代表左右子树层级相差超过1层,或者最后一层没有左节点却有右节点
if (index !== ++count) {
return false
}
// 层序遍历过程中,用index来维护节点索引,如果根节点index为1,那么一个节点索引是index,那他的左孩子索引是index * 2,右孩子索引是index * 2 +1
node.left && queue.push({ node: node.left, index: index * 2 })
node.right && queue.push({ node: node.right, index: index * 2 + 1 })
}
return true
};
leetcode 965. 单值二叉树
题目地址:单值二叉树

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isUnivalTree = function(root) {
if (!root) {
return true
}
const val = root.val
function _isUnivalTree (root) {
if (root) {
if (root.val != val) {
return false
} else {
return _isUnivalTree(root.left) && _isUnivalTree(root.right)
}
} else {
return true
}
}
return _isUnivalTree(root)
};
leetcode 1008. 先序遍历构造二叉树
题目地址:先序遍历构造二叉树

/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {number[]} preorder
* @return {TreeNode}
*/
var bstFromPreorder = function(preorder) {
const len = preorder.length
if (!len) {
return null
}
const left = []
const right = []
const rootVal = preorder[0]
const root = new TreeNode(rootVal)
for (let i = 1; i < len; i++) {
const nodeVal = preorder[i]
nodeVal > rootVal ? right.push(nodeVal) : left.push(nodeVal)
}
root.left = bstFromPreorder(left)
root.right = bstFromPreorder(right)
return root
};