重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/
9 20
/
15 7
限制:
0 <= 节点个数 <= 5000
java
做这题之前我们先来看一下树的几种遍历顺序。
先序遍历:根节点→左子树→右子树。
中序遍历:左子树→根节点→右子树。
后续遍历:左子树→右子树→根节点。
其实也很好记,他是根据根节点遍历的顺序来定义的,比如先遍历根节点就是先序遍历,中间遍历根节点就是中序遍历,最后遍历根节点就是后续遍历,至于左子树和右子树哪个先遍历,记住一点,这3种遍历顺序右节点永远都不可能比左节点先遍历。如果还不懂的可以看下之前写的373,数据结构-6,树。
我们就以上面的示例数据来看下,前序遍历是[3,9,20,15,7],前序遍历先访问的是根节点,所以3就是根节点。中序遍历是[9,3,15,20,7],由于中序遍历是在左子树都遍历完的时候才遍历根节点,所有在中序遍历中3前面的都是3的左子树节点,3后面的都是3的右子树节点。也就是下面这样
然后我们再使用同样的方式对左右子树继续划分,一直这样下去,直到不能再分为止,我们来看下代码
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
//把前序遍历的值和中序遍历的值放到list中
List<Integer> preorderList = new ArrayList<>();
List<Integer> inorderList = new ArrayList<>();
for (int i = 0; i < preorder.length; i++) {
preorderList.add(preorder[i]);
inorderList.add(inorder[i]);
}
return helper(preorderList, inorderList);
}
private TreeNode helper(List<Integer> preorderList, List<Integer> inorderList) {
if (inorderList.size() == 0)
return null;
//前序遍历的第一个值就是根节点
int rootVal = preorderList.remove(0);
//创建跟结点
TreeNode root = new TreeNode(rootVal);
//查看根节点在中序遍历中的位置,然后再把中序遍历的数组劈两半,前面部分是
//根节点左子树的所有值,后面部分是根节点右子树的所有值
int mid = inorderList.indexOf(rootVal);
//[0,mid)是左子树的所有值,inorderList.subList(0, mid)表示截取inorderList
//的值,截取的范围是[0,mid),包含0不包含mid。
root.left = helper(preorderList, inorderList.subList(0, mid));
//[mid+1,inorderList.size())是右子树的所有值,
// inorderList.subList(mid + 1, inorderList.size())表示截取inorderList
//的值,截取的范围是[mid+1,inorderList.size()),包含mid+1不包含inorderList.size()。
root.right = helper(preorderList, inorderList.subList(mid + 1, inorderList.size()));
return root;
}
}
python
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def buildTree(self, preorder, inorder):
"""
:type preorder: List[int]
:type inorder: List[int]
:rtype: TreeNode
"""
if not preorder:
return None
#创建当前节点
node = TreeNode(preorder[0])
#查找当前的根节点在中序遍历中的位置
index = inorder.index(preorder[0])
# 划分左右子树
left_pre = preorder[1:index+1]
left_in = inorder[:index]
right_pre = preorder[index+1:]
right_in = inorder[index+1:]
# 遍历创建子树
node.left = self.buildTree(left_pre, left_in)
node.right = self.buildTree(right_pre, right_in)
# 返回当前节点
return node
我们需要根据这两个序列划分,我们知道前序遍历的第一个节点为头结点,在这了头结点为[3],我们在中序遍历中找到[3]所在的位置,可以看到位于中序遍历的第二个位置,那么我们可以确定[3]的左子树的节点包含[9],右子树节点包含[20,25,7],一直这样划分下去,直到数组为空,在返回节点.