题目来源:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/
大致题意:
给一个二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点
思路
已知前序遍历的顺序为 (根,左子树,右子树),中序遍历的顺序为(左子树,根,右子树)
于是可以通过前序遍历当前第一个元素获取到根节点,根据根节点在中序中的位置获取左子树和右子树的范围,然后递归构建左子树和右子树
具体实现时可以通过哈希表存下中序遍历时每个节点对应的位置,这样可以在 O(1) 的时间复杂度获取到根节点在中序遍历的位置,并根据位置获取左子树和右子树的节点范围
大致的解题思路为
- 使用哈希表存下中序遍历时每个节点对应的位置
- 递归建树:使用方法
getChild(int preorderLeft, int preorderRight, int inorderLeft, int inorderRight)
获取前序索引 [preorderLeft, preorderRight],中序索引 [inorderLeft, inorderRight] 这一段子树的根节点
在方法
getChild(int preorderLeft, int preorderRight, int inorderLeft, int inorderRight)
中,
若前序索引的开始位置大于结束位置,证明不存在对应子树,返回空。
已知前序遍历的第一个节点即为当前的根节点,直接创建已前序遍历第一个元素为值的节点作为当前子树的根节点
然后根据当前根节点在中序遍历中的位置获取左右子树的索引范围,递归获取当前根节点的左右子树
最终返回根节点即可
- 以当前子树的根节点为键,从哈希表中获取在中序遍历中的位置 i,那么
size = i - inorderLeft (即中序遍历起始位置)
即为当前节点的左子树中的节点数量,于是左子树在前序遍历中的索引范围为 [preorderLeft + 1, preorderLeft + size],在中序遍历中的索引范围为 [inorderLeft, i - 1] - 同理可得前序遍历右子树索引范围为 [preorderLeft + size + 1, preorderRight], 中序遍历右子树索引范围为 [i + 1, inorderRight]
代码:
class Solution {
// 存中序遍历中节点对应的索引位置
Map<Integer, Integer> idxMap;
public TreeNode buildTree(int[] preorder, int[] inorder) {
idxMap = new HashMap<>();
int m = preorder.length;
int n = inorder.length;
// 获取中序遍历中节点对应的索引位置
for (int i = 0; i < n; i++) {
idxMap.put(inorder[i], i);
}
return getChild(preorder, inorder, 0, m - 1, 0, n - 1);
}
// 获取前序索引范围 [preorderLeft, preorderRight] 的子树根节点
public TreeNode getChild(int[] preorder, int[] inorder, int preorderLeft, int preorderRight, int inorderLeft, int inorderRight) {
// 不合理,返回空
if (preorderLeft > preorderRight) {
return null;
}
// 获取子树根节点
TreeNode root = new TreeNode(preorder[preorderLeft]);
// 获取根节点在中序中的索引
int inorderRootIdx = idxMap.get(preorder[preorderLeft]);
// 获取子树的左子树的节点数量
int leftChildCount = inorderRootIdx - inorderLeft;
// 递归获取子树左子树的根节点
root.left = getChild(preorder, inorder, preorderLeft + 1, preorderLeft + leftChildCount, inorderLeft, inorderRootIdx - 1);
// 递归获取子树右子树的根节点
root.right = getChild(preorder, inorder, preorderLeft + leftChildCount + 1, preorderRight, inorderRootIdx + 1, inorderRight);
return root;
}
}