题目来源:https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
问题描述
Medium
155841FavoriteShare
Given preorder and inorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
For example, given
preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]
Return the following binary tree:
3
/ \
9 20
/ \
15 7
------------------------------------------------------------
题意
给定一个二叉树的先序遍历和中序遍历,构造这棵二叉树。(已知二叉树的每个节点的值各不相同)
------------------------------------------------------------
思路
递归实现。递归函数通过子树的先序遍历和中序遍历构造子树并返回子树的根节点。具体来说,递归函数的输入是先序遍历数组、中序遍历数组、子树在先序遍历数组中的开始地址、子树在中序遍历数组中的开始地址、子树在先序/中序数组中的长度,返回值是子树的根节点。在递归函数体内,首先通过先序遍历数组和子树在先序遍历数组中的开始地址构造子树的根节点,然后在中序遍历数组中查找子树根节点的值,由子树根节点在中序遍历数组中的地址和中序遍历数组的开始地址可以计算出左子树的长度,再根据子树在先序/中序数组中的长度可以计算出右子树的长度,由此可以递归调用构造出左子树和右子树,将左子树的根节点作为当前子树根节点的左子女,将右子树的根节点作为当前子树根节点的右子女。最后返回当前子树的根节点。
【举一反三】
已知中序遍历和后序遍历也可以重建出二叉树(思路大抵相同,只是找子树的根节点要去后序遍历的尾地址找)。
但是已知先序遍历和后序遍历是构造不出唯一的二叉树的,可能会有多种情况。下面就是一个例子:
1 1
/ \
2 2
两棵树的先序遍历都是[1, 2],后序遍历都是[2, 1]。由此可见,先序遍历和后序遍历放在一起不能构造出二叉树的原因是存在左子树或右子树为空的情形时,无法确定除根节点外的部分究竟属于左子树还是属于右子树。
------------------------------------------------------------
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
/**
find index of {@code value} in array {@code arr} beginning at {@code begin} with valid length {@code len}
*/
private int findVal(int[] arr, int begin, int len, int value)
{
for (int i = begin; i < begin + len; i++)
{
if (arr[i] == value)
{
return i;
}
}
return -1;
}
/**
construct a subtree defined by preorder[prehead:prehead+sublen] & inorder[inhead:inhead+sublen]
{@code preorder}: preorder array
{@code inorder}: inorder array
{@code prehead}: begin of subtree in {@code preorder}
{@code inhead}: begin of subtree in {@code inorder}
{@code sublen}: length of subtree
return: root node of subtree
*/
private TreeNode subTree(int[] preorder, int[] inorder, int prehead, int inhead, int sublen)
{
if (sublen == 0)
{
return null;
}
TreeNode root = new TreeNode(preorder[prehead]);
int in_root = findVal(inorder, inhead, sublen, preorder[prehead]);
root.left = subTree(preorder, inorder, prehead+1, inhead, in_root - inhead);
root.right = subTree(preorder, inorder, prehead+1+in_root-inhead, in_root+1, sublen-in_root+inhead-1);
return root;
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
return subTree(preorder, inorder, 0, 0, preorder.length);
}
}