leetcode
leetcode 2551 ~ 2600
推理二叉树

推理二叉树

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 224 ms, 内存: 19.1 MB


/*
 * 思路:
 * 1. 前序遍历的第一个元素是根节点。
 * 2. 在中序遍历中找到根节点的位置,其左边是左子树,右边是右子树。
 * 3. 递归构建左子树和右子树。
 * 4. 使用 Java Stream API 简化代码。
 */

import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

public class Solution {
    private Map<Integer, Integer> inorderIndexMap;
    private int preorderIndex;

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        preorderIndex = 0;
        inorderIndexMap = IntStream.range(0, inorder.length).boxed().collect(Collectors.toMap(i -> inorder[i], i -> i));
        return helper(preorder, 0, inorder.length - 1);
    }

    private TreeNode helper(int[] preorder, int inorderStart, int inorderEnd) {
        if (inorderStart > inorderEnd) {
            return null;
        }

        int rootVal = preorder[preorderIndex++];
        TreeNode root = new TreeNode(rootVal);
        int inorderIndex = inorderIndexMap.get(rootVal);

        root.left = helper(preorder, inorderStart, inorderIndex - 1);
        root.right = helper(preorder, inorderIndex + 1, inorderEnd);

        return root;
    }
}

解释

方法:

此题解采用的是递归的方式来构建二叉树。首先根据前序遍历的第一个元素确定树的根节点,然后在中序遍历中找到该根节点,从而区分出左子树和右子树的中序遍历。利用中序遍历中左、右子树的长度,可以相应地从前序遍历中划分出左右子树的前序遍历序列。这样,递归地对左右子树进行相同的构建过程,直到所有的子树都被正确构建。

时间复杂度:

O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在题解中在中序遍历数组中查找根节点的索引时不直接使用哈希表,而是选择了线性搜索?
在题解中使用线性搜索而不使用哈希表来查找中序遍历数组中的根节点索引,可能是出于简化代码的考虑或假设输入规模较小而搜索开销不大。使用哈希表虽然可以将索引查找的时间复杂度降低到O(1),提高效率,但会增加额外的空间复杂度。对于小规模数据,这种时间复杂度的提升可能不明显,而额外的空间复杂度则可能成为负担。然而,在处理大规模数据时,使用哈希表来优化查找效率确实是一种更优的选择。
🦆
在构建左右子树的递归调用中,为何左子树的递归结束条件是`pstart+left_length`而右子树的开始条件是`pstart+left_length+1`?这里的+1是如何确定的?
在递归构建二叉树的过程中,`pstart+left_length`是左子树在前序遍历序列中的最后一个元素的位置,因此这确定了左子树的边界。右子树在前序遍历中的开始位置是`pstart+left_length+1`,这里的+1表明跳过了当前的根节点,直接移动到右子树的第一个元素。这是因为前序遍历的顺序是根节点后紧跟左子树,再跟右子树,且左子树的长度正是由中序遍历中的根节点位置决定。
🦆
题解中的递归函数`build`在何种情况下会返回`None`?这是否意味着在某些情况下子树可能不存在?
递归函数`build`会在`pstart`大于`pend`时返回`None`,这发生在二叉树的某个分支不存在任何节点时,比如某个节点不存在左子树或右子树。在这种情况下,递归的边界条件`pstart > pend`成立,意味着不存在更多的节点可以用来构建子树,因此返回`None`表示该子树为空。这确实意味着在某些情况下子树可能不存在,这在不完全二叉树中是常见的情形。
🦆
在这种树的构建方法中,是否有可能通过优化递归过程来进一步提高算法性能?例如通过尾递归优化等技术?
在这种树的构建方法中,优化递归过程确实可以提高算法性能。然而,尾递归优化在这个场景下可能不太适用,因为树的构建本质上需要处理两个递归分支(左子树和右子树),并且它们的处理依赖于前一个递归的结果。这不符合尾递归的条件,因为尾递归要求最后一个操作必须是递归调用本身。更有效的优化方法可能包括使用哈希表来优化中序遍历的索引查找,从而减少查找时间,或者重新设计递归逻辑,减少不必要的计算和空间消耗。

相关问题