本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目来源:leetcode-cn.com/problems/zh…
大致题意: 给一个二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点
思路
- 使用哈希表存下中序遍历时每个节点对应的位置
- 递归建树:使用方法
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 - 同理可得右子树根节点
代码:
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;
}
}