「这是我参与2022首次更文挑战的第37天,活动详情查看:2022首次更文挑战」。
题目:给定一颗二叉树的先序和中序遍历结果,要求根据此结果恢复二叉树,并且返回二叉树的根节点。
解题思路
给定一颗二叉树的先序序列preOrder和中序序列inOrder,我们可以直接恢复成一颗二叉树,假如preOrder=[3,9,20,15,7],inOrder=[9,3,15,20,7],恢复过程如下:
根据先序序列,首先知道3为这棵树的根节点,之后在中序序列中找到3,则3的左边为根节点的左子树,3的右边为根节点的右子树。因为中序序列3的左边只有9,因此确定9为3的左子树。之后还剩20、15、7三个节点,根据先序序列可知20为右子树的根节点,而15和7由中序序列可知分别为20的左子树和右子树。因此恢复的二叉树就如下:
上述过程实际上就是一个递归,对于先序序列preOrder和中序序列inOrder,可得下面的示意图:
首先在inOrder中确定根节点的索引位置,则inOrder的index左边即为左子树,右边即为右子树。如果直接通过遍历获取根节点的索引,时间复杂度会增大,因此我们可以事先将inOrder的数据和对应索引存入map中,之后在map中查询即可,又因为inOrder左子树的长度和preOrder的左子树长度是相同的。因此可以确定preOrder的边界的索引,如下图:
根据上面索引,可得如下代码:
public TreeNode buildTree(int[] preorder, int[] inorder) {
HashMap<Integer, Integer> map = new HashMap<>();
for(int i=0;i<inorder.length;i++){
map.put(inorder[i], i);
}
return buildTree(preorder, 0, preorder.length-1, 0, inorder.length-1, map);
}
private TreeNode buildTree(int[] preorder, int preleft, int preright, int inleft, int inright, HashMap<Integer, Integer> map) {
if(preleft>preright||inleft>inright) return null;
int value = preorder[preleft];
TreeNode root = new TreeNode(value);
Integer index = map.get(value);
root.left = buildTree(preorder, preleft+1, index-inleft+preleft, inleft, index-1, map);
root.right = buildTree(preorder, index-inleft+preleft+1, preright, index+1, inright, map);
return root;
}
上述代码的时间复杂度和空间复杂度都为。