根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
前序遍历可以判断节点的父子关系
中序遍历可以判断节点的左右关系
两者加起来可以判断出所有节点的父子 左右关系 因此可以构建出唯一二叉树
二叉树的构建一般通过递归实现 先找当前子树的根节点, 再递归构造左右子树
class Solution {
private Map<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
for (int i = 0; i < inorder.length; i ++) {
map.put(inorder[i], i);
}
return deep(preorder, inorder, 0, preorder.length - 1, 0, inorder.length - 1);
}
// pi~pj 当前子树在前序数组中的位置范围 ii~ij 当前子树在中序数组中的位置范围
private TreeNode deep(int[] preorder, int[] inorder, int pi, int pj, int ii, int ij) {
TreeNode root = new TreeNode(preorder[pi]);
if (pi == pj) {
return root;
}
// 找到当前根节点在两个数组中的位置
int rootEle = preorder[pi];
int midIndex = -1;
for (int z = ii; z <= ij; z++) {
if (inorder[z] == rootEle) {
midIndex = z;
}
}
int leftO = pi ;
for (int z = pi + 1; z <= pj; z++) {
if (map.get(preorder[z]) > map.get(inorder[midIndex])) {
break;
} else {
leftO = z;
}
}
if (midIndex == ii) {
root.left = null;
} else {
root.left = deep(preorder, inorder, pi + 1, leftO, ii, midIndex - 1);
}
if (midIndex == ij) {
root.right = null;
} else {
root.right = deep(preorder, inorder, leftO + 1, pj, midIndex + 1, ij);
}
return root;
}
}
上面算法比较慢,主要是在确定中序数组中的根节点和前序数组中的左子树边界存在两次遍历,如果数组较长 耗时会多。
优化:
- 在找中序数组中的根节点位置时直接通过 map 查找
- 在中序数组中找到根节点后,可以快速确定左右子树的长度,这时候已经可以根据长度确定前序数组中左右子树的边界 不需要再做遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
private Map<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
for (int i = 0; i < inorder.length; i ++) {
map.put(inorder[i], i);
}
return deep(preorder, inorder, 0, preorder.length - 1, 0, inorder.length - 1);
}
private TreeNode deep(int[] preorder, int[] inorder, int pi, int pj, int ii, int ij) {
TreeNode root = new TreeNode(preorder[pi]);
if (pi == pj) {
return root;
}
int rootEle = preorder[pi];
int midIndex = map.get(rootEle);
int leftLen = midIndex - ii ;
if (midIndex == ii) {
root.left = null;
} else {
root.left = deep(preorder, inorder, pi + 1, pi + leftLen, ii, midIndex - 1);
}
if (midIndex == ij) {
root.right = null;
} else {
root.right = deep(preorder, inorder, pi + leftLen + 1, pj, midIndex + 1, ij);
}
return root;
}
}