力扣 剑指 Offer 07. 重建二叉树

题目来源:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/

大致题意:
给一个二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点

思路

已知前序遍历的顺序为 (根,左子树,右子树),中序遍历的顺序为(左子树,根,右子树)

于是可以通过前序遍历当前第一个元素获取到根节点,根据根节点在中序中的位置获取左子树和右子树的范围,然后递归构建左子树和右子树

具体实现时可以通过哈希表存下中序遍历时每个节点对应的位置,这样可以在 O(1) 的时间复杂度获取到根节点在中序遍历的位置,并根据位置获取左子树和右子树的节点范围

大致的解题思路为

  1. 使用哈希表存下中序遍历时每个节点对应的位置
  2. 递归建树:使用方法 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]
  • 同理可得前序遍历右子树索引范围为 [preorderLeft + size + 1, preorderRight], 中序遍历右子树索引范围为 [i + 1, inorderRight]

代码:

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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值