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

80 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目来源:leetcode-cn.com/problems/zh…

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

思路

  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
  • 同理可得右子树根节点

代码:

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;
    }
}