树
# 树
[TOC]
# 一、二叉树
思路:自顶向下 自底向上; 递归 遍历;特况 一般。
特况要考虑root为null、root.left为null或root.right为null的情况。
递归参数不要出现left、right,因为会出现left和right不同时有的情况。
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
1
2
3
4
5
6
7
2
3
4
5
6
7
# 1.1 leetcode-100-相同的树
给定两个二叉树,编写一个函数来检验它们是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
/**
* @param {TreeNode} p
* @param {TreeNode} q
* @return {boolean}
*/
var isSameTree = function(p, q) {
if(!p && !q) return true
if(!p && q) return false
if(p && !q) return false
if(p.val === q.val) return isSameTree(p.left, q.left) && isSameTree(p.right, q.right)
else return false
};
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 1.2 leetcode-101-对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isSymmetric = function (root) {
return isMirror(root, root)
function isMirror(tree1, tree2) {
// 1. 特况
if (!tree1 && !tree2) return true
if (!tree1 || !tree2) return false
// 2. 一般
return (tree1.val === tree2.val) && isMirror(tree1.right, tree2.left) && isMirror(tree2.right, tree1.left)
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1.3 leetcode-104-二叉树的最大深度
给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明: 叶子节点是指没有子节点的节点。
/**
* @param {TreeNode} root
* @return {number}
*/
var maxDepth = function(root, deep=0) {
if(!root) return deep
else deep++
return Math.max(maxDepth(root.left, deep), maxDepth(root.right, deep))
};
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 1.4 leetcode-107-二叉树的层次遍历II
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var levelOrderBottom = function(root) {
let res = []
if(root === null) return res
let val = [], nextNode = [], node = [root]
while(node.length) {
val = []
nextNode = []
node.forEach(item => {
val.push(item.val)
if(item.left!==null) {
nextNode.push(item.left)
}
if(item.right!==null) {
nextNode.push(item.right)
}
})
res.unshift(val)
node = nextNode
}
return res
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 1.5 leetcode-110-平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
/**
* @param {TreeNode} root
* @return {boolean}
*/
var isBalanced = function (root) {
// 要么返回左右子树的相对高度,要么返回-1表明不是平衡树
function recur(root) {
if (root === null) return 0
let left = recur(root.left)
if (left === -1) return -1
let right = recur(root.right)
if (right === -1) return -1
if (Math.abs(left - right) >= 2) {
return -1
} else {
return Math.max(left, right) + 1
}
}
return recur(root) !== -1
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1.6 leetcode-111-二叉树的最小深度
给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。说明: 叶子节点是指没有子节点的节点。
/**
* @param {TreeNode} root
* @return {number}
*/
var minDepth = function (root) {
if (!root) return 0
return findMin(root, 1)
function findMin(tree, depth) {
if (!tree.left && !tree.right) return depth
if (!tree.left && tree.right) return findMin(tree.right, depth + 1)
if (tree.left && !tree.right) return findMin(tree.left, depth + 1)
return Math.min(findMin(tree.left, depth + 1), findMin(tree.right, depth + 1))
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1.7 leetcode-112-路径总和
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
var hasPathSum = function (root, sum) {
if (!root) return false
sum -= root.val
if (!root.left && !root.right) return sum === 0
return hasPathSum(root.left, sum) || hasPathSum(root.right, sum)
};
1
2
3
4
5
6
2
3
4
5
6
# 1.8 leetcode-226-翻转二叉树
翻转一棵二叉树。
var invertTree = function (root) {
if(!root) return root
let left = null, right = null
if(root.left) left = root.lleeft
if(root.right) right = root.right
if (!left && !right) return root
root.left = invertTree(right)
root.right = invertTree(left)
return root
};
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 1.9 leetcode-235-二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
说明:
- 所有节点的值都是唯一的。
- p、q 为不同节点且均存在于给定的二叉搜索树中。
var lowestCommonAncestor = function(root, p, q) {
// 利用二叉搜索树的性质
// 根结点比两个结点大,就在左子树找
// 根结点比两个结点小,就在右子树找
// 否则,返回根结点
if(root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q)
if(root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q)
return root
};
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 1.10 leetcode-257-二叉树的所有路径
给定一个二叉树,返回所有从根节点到叶子节点的路径。
var binaryTreePaths = function(root) {
if(!root) return []
if(!root.left && !root.right) return [root.val.toString()]
let left = binaryTreePaths(root.left)
let right = binaryTreePaths(root.right)
return left.concat(right).map(item => root.val+'->'+item)
};
1
2
3
4
5
6
7
2
3
4
5
6
7
# 1.11 重建二叉树
- 题目 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
前序遍历:根左右;中序遍历:左根右。
- 解法
/* function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
} */
function reConstructBinaryTree(pre, vin)
{
if(pre.lenght==0||vin.length==0) return null;
let root=pre[0];
let vinRootIndex = vin.indexOf(root);
let vinLeft=vin.slice(0,vinRootIndex);
let vinRight=vin.slice(vinRootIndex+1);
let preLeft=pre.slice(1,vinLeft.length+1);
let preRight=pre.slice(vinLeft.length+1);
let node={
val:root,
left:reConstructBinaryTree(preLeft,vinLeft),
right:reConstructBinaryTree(preRight,vinRight)
};
return node;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 返回的结果
1. *{val: 1, left: {…}, right: {…}}*
2. 1. left:
2. 1. left:
2. 1. left: null
2. right:
3. 1. left: null
2. right: null
3. val: 7
4. __proto__: Object
4. val: 4
5. __proto__: Object
3. right: null
4. val: 2
5. __proto__: Object
3. right:
4. 1. left: {val: 5, left: null, right: null}
2. right: {val: 6, left: {…}, right: null}
3. val: 3
4. __proto__: Object
5. val: 1
6. __proto__: Object
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 1.12 leetcode-637-二叉树的层平均值
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。
输入:
3
/ \
9 20
/ \
15 7
输出:[3, 14.5, 11]
1
2
3
4
5
6
7
2
3
4
5
6
7
显而易见,此题用到的是BFS
。
let node = { val: 3, left: { val: 9, left: null, right: null }, right: { val: 20, left: { val: 15, left: null, right: null }, right: { val: 7, left: null, right: null } } };
var averageOfLevels = function (root) {
let res = [];
if (!root) return res;
res = [root.val];
let queue = [root];
while (queue.length) {
let num = 0;
let nextLevel = [];
queue.forEach(item => {
if (item.left) {
nextLevel.push(item.left);
num += item.left.val;
}
if (item.right) {
nextLevel.push(item.right);
num += item.right.val;
}
})
nextLevel.length && res.push(num / nextLevel.length)
queue = nextLevel;
}
return res;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 二、多叉树
数据结构
[{key: a, children: [{key: b, children: null}]},{key: c, children: null}]
# 2.1 相关计算
# 2.1.1 获取子树
function getChildTree(data, key) {
return getChidTreeFn(data);
function getChidTreeFn(data) {
if (data) {
if (Array.isArray(data)) {
let res = null;
for (let item of data) {
res = getChidTreeFn(item);
if (res) break;
}
return res;
} else if (data.key === key) {
return data;
} else return getChidTreeFn(data.children);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2.1.2 获取父级key
function getParent(data, key) {
if (typeof data === "object" && data) {
let val = Array.isArray(data) ? [] : {};
for (let i in data) {
val[i] = getParent(data[i], key);
if (i === "children" && val[i]) {
console.log('children', val[i])
val[i].forEach(item => {
console.log('111', item, item.key, key, item.key === key)
if (item.key === key) {
console.log('父元素', val.key);
}
});
}
}
return val
} else {
return data
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2.1.3 获取叶子结点
function getAllLeaf(data) {
let result = [];
function getLeaf(data) {
if (Array.isArray(data)) {
data.forEach(item => {
if (!item.children) {
result.push(item.key);
} else {
getLeaf(item.children);
}
});
} else {
if (!data.children) {
result.push(data.key);
} else {
getLeaf(data.children);
}
}
}
getLeaf(data);
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 2.1.4 获取根结点到叶子结点的路径
- 方法一:如果是叶子结点,就更新路径,并存起来;如果不是则只更新路径,继续遍历。
function getAllPath(data) {
let paths = []
getAllPathFn(data)
return paths
function getAllPathFn(data, path = []) {
data.forEach(i => {
if (!i.children) {
path.push(i.key)
paths.push(path)
} else {
let tmp = JSON.parse(JSON.stringify(path))
tmp.push(i.key)
getAllPathFn(i.children, tmp)
}
})
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- 方法二:
function fn(list){
let path=''
let oldPath=''
let result={}
function handle(data,_path){
for(let item of data){
result[item.key]=_path?_path+'-'+item.key:_path+item.key
if(item.children){
handle(item.children,result[item.key])
}
}
}
handle(list,path)
return result
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15