# 从前序与中序遍历序列构造二叉树
给定一棵树的前序遍历 preorder 与中序遍历 inorder。请构造二叉树并返回其根节点。
示例 1:
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
示例 2:
Input: preorder = [-1], inorder = [-1]
Output: [-1]
提示:
1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder 和 inorder 均无重复元素
inorder 均出现在 preorder
preorder 保证为二叉树的前序遍历序列
inorder 保证为二叉树的中序遍历序列
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
# 方案 1: 递归
// https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/cong-qian-xu-yu-zhong-xu-bian-li-xu-lie-gou-zao-9/
function buildTree(preorder, inorder) {
function myBuildTree(preorderLeft, preorderRight, inorderLeft, inorderRight) {
if (preorderLeft > preorderRight) {
return null;
}
// 前序遍历第一个节点就是根节点
let preorderRoot = preorderLeft;
// 在中序遍历中定位根节点
let inorderRoot = indexMap[preorder[preorderRoot]];
// 先把根节点建立起来
let root = new TreeNode(preorder[preorderRoot]);
// 得到左子树中的节点数目
let sizeLeftSubtree = inorderRoot - inorderLeft;
// 递归地构造左子树,并连接到根节点
// 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root.left = myBuildTree(
preorderLeft + 1,
preorderLeft + sizeLeftSubtree,
inorderLeft,
inorderRoot - 1
);
// 递归地构造右子树,并连接到根节点
// 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
root.right = myBuildTree(
preorderLeft + sizeLeftSubtree + 1,
preorderRight,
inorderRoot + 1,
inorderRight
);
return root;
}
let n = preorder.length;
let indexMap = {};
for (let i = 0; i < n; i++) {
indexMap[inorder[i]] = i; // 记录 inorder 的每个数字所在索引
}
return myBuildTree(0, n - 1, 0, n - 1);
}
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
37
38
39
40
41
42
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
37
38
39
40
41
42
# 方法 2: 递归
// 参数相比1少了一些,另外 inorder 位置查找改成了 while 查找
var buildNode = function(preorder, inorder) {
if (!preorder.length) return null;
// 查找根结点在中序遍历中的位置
let p = 0;
while (inorder[p] !== preorder[0]) {
p++;
}
// 构建根节点
let root = new TreeNode(preorder[0]);
let leftIn = inorder.slice(0, p); // 左子树 中序数组
let rightIn = inorder.slice(p + 1); // 右子树 中序数组
let leftPr = preorder.slice(1, p + 1); // 左子树 前序数组
let rightPr = preorder.slice(p + 1); // 右子树 前序数组
root.left = buildNode(leftPr, leftIn);
root.right = buildNode(rightPr, rightIn);
return root;
};
var buildTree = function(preorder, inorder) {
return buildNode(preorder, inorder);
};
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
# 方案 3: 迭代
// https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/cong-qian-xu-yu-zhong-xu-bian-li-xu-lie-gou-zao-9/
function buildTree(preorder, inorder) {
if (!preorder) {
return null;
}
let root = new TreeNode(preorder[0]);
let stack = [root];
let inorderIndex = 0;
for (let i = 1; i < preorder.length; i++) {
let preorderVal = preorder[i];
let node = stack[stack.length - 1];
if (node.val !== inorder[inorderIndex]) {
node.left = new TreeNode(preorderVal);
stack.push(node.left);
} else {
while (
stack &&
stack.length &&
stack[stack.length - 1].val === inorder[inorderIndex]
) {
node = stack.pop();
inorderIndex += 1;
}
node.right = new TreeNode(preorderVal);
stack.push(node.right);
}
}
return root;
}
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
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