剑指offer刷题(五)难点

重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如,给出

前序遍历 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],一直这样划分下去,直到数组为空,在返回节点.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值