lotus

贵有恒何必三更眠五更起 最无益只怕一日曝十日寒

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

1. 题目

 

 

 

考察点

考察点是二叉树的遍历和构造,以及分治法的应用

  • 二叉树的遍历有前序遍历,中序遍历和后序遍历三种方式,它们的区别在于根节点的访问顺序。前序遍历是先访问根节点,再访问左子树,最后访问右子树。中序遍历是先访问左子树,再访问根节点,最后访问右子树。后序遍历是先访问左子树,再访问右子树,最后访问根节点。
  • 二叉树的构造是根据给定的遍历序列,还原出原始的二叉树结构。这道题给定了前序遍历和中序遍历两种序列,我们可以利用它们的特点来确定每个子树的范围和根节点的位置。
  • 分治法是一种解决复杂问题的思想,它将一个大问题分解为若干个相同或相似的小问题,然后递归地求解小问题,最后合并小问题的解得到大问题的解。这道题就可以用分治法来实现,我们可以将每个子树看作一个小问题,然后递归地构造左右子节点,最后返回根节点。

 

2. 解法

代码的逻辑如下:

  • 首先,我们定义一个递归函数,它接收前序数组,中序数组,以及各自的起始和结束位置作为参数。
  • 在递归函数中,我们首先判断前序或中序数组是否为空,如果是,就返回null,表示没有子树。
  • 然后,我们从前序数组中取出第一个元素,这个元素就是当前子树的根节点的值,我们创建一个新的树节点,并将其赋值为这个元素。
  • 接着,我们在中序数组中查找这个元素的位置,这个位置就是根节点在中序遍历中的位置,我们用一个哈希表来存储每个值对应的索引,这样可以加快查找的速度。
  • 根据这个位置,我们可以将中序数组分为左右两部分,左边的部分就是左子树的中序遍历,右边的部分就是右子树的中序遍历。我们可以计算出左子树的节点个数,然后根据这个个数,在前序数组中确定左右子树的范围。
  • 最后,我们递归地调用自己,构造左右子节点,并将它们分别赋值给根节点的左右指针。然后返回根节点。
 
 

具体实现

class Solution {
    // 使用一个哈希表存储中序遍历中每个值对应的索引,方便查找
    Map<Integer, Integer> inorderMap = new HashMap<>();

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        // 遍历中序数组,将值和索引存入哈希表
        for (int i = 0; i < inorder.length; i++) {
            inorderMap.put(inorder[i], i);
        }
        // 调用递归函数,传入前序数组,中序数组,以及各自的起始和结束位置
        return buildTree(preorder, inorder, 0, preorder.length - 1, 0, inorder.length - 1);
    }

    private TreeNode buildTree(int[] preorder, int[] inorder, int preStart, int preEnd, int inStart, int inEnd) {
        // 如果前序或中序数组为空,返回null
        if (preStart > preEnd || inStart > inEnd) {
            return null;
        }
        // 前序数组的第一个元素是根节点的值
        int rootVal = preorder[preStart];
        // 创建根节点
        TreeNode root = new TreeNode(rootVal);
        // 在中序数组中找到根节点的索引
        int inRoot = inorderMap.get(rootVal);
        // 计算左子树的节点个数
        int leftSize = inRoot - inStart;
        // 递归构造左子树,更新前序和中序数组的起始和结束位置
        root.left = buildTree(preorder, inorder, preStart + 1, preStart + leftSize, inStart, inRoot - 1);
        // 递归构造右子树,更新前序和中序数组的起始和结束位置
        root.right = buildTree(preorder, inorder, preStart + leftSize + 1, preEnd, inRoot + 1, inEnd);
        // 返回根节点
        return root;
    }
}

  

3. 总结

posted on 2023-04-25 13:54  白露~  阅读(8)  评论(0编辑  收藏  举报