图解二叉树的构造 | 中序 + 后序

该文详细介绍了如何根据中序和后续遍历的数组结果,利用递归方法构造二叉树。关键步骤包括确定递归函数、设置终止条件以及计算左右子树的大小和下标范围。通过获取根节点值和在中序遍历中的位置,可以有效地划分并构建左右子树。
摘要由CSDN通过智能技术生成

中序后续构造二叉树

https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/

递归思路

递归思路很简单, 因为无论是构造一棵大树还是一棵小树, 都是重复的子问题, 思路主要麻烦在边界上

如下图所示

image-20230116210739732

上述是中序和后续序列

我们要递归, 需要首先确定递归函数, 因为题目是以数组形式, 我们如果要取数据, 需要开始和结束下标, 所以递归函数的下标是

public TreeNode buildTree(int[] inorder, int inStart, int inEnd,int[] postorder, int postStart, int postEnd)

下一步是终止条件, 因为是给定了下标, 如果下标不合法, 说明到达终止条件, 因为递归的话, 需要不断去划分左右子树

  if(inStart > inEnd) {
      return null;
    }

最后是当前层的执行逻辑 :

  • 构造根节点
  • 构造左子树和右子树
    • 获取左子树的中序和后续数组开始和结束下标
    • 获取右子树的中序和后续数组开始和结束下标
image-20230116211345614

麻烦的就是下标边界问题, 很容易写错, 其实也很简单 :

image-20230116212437768

如上图 :

  1. 中序的下标很好判断, 只要找到根节点的下标即可
  2. 后序的话, 因为是左右根的节点顺序, 所以计算出 leftsize , 也就是左子树的节点数, 就可以计算出新的左子树
  3. 计算 leftSize = rootValIndex - inStart 这个结果其实就是计算 rootValIndex 向左走 leftSize 步
  4. inStart + leftSize 等于初始位置向右移动 leftSize 步
 			// 1. 获取根节点的值
            int rootVal = postorder[postEnd];
            // 2. 获取根节点在中序的下标
            int rootValIndex = valueToIdx.get(rootVal);

            // 计算左子树的大小
            // [1,2, {3}, 4,5,6]
            // 中值是 3 : leftSize = 2 - 0 = 2
            // rightSize = 5 - 2 = 3
            int leftSize = rootValIndex - inStart;
            
            // 新的中序开始/结束下标
            // 左子树
            int newLeftInStart = inStart;
            int newLeftInEnd = rootValIndex - 1;
            // 右子树
            int newRightInStart = rootValIndex + 1;
            int newRightInEnd = inEnd;

            // 新的后序开始/结束下标
            // 左子树
            int newLeftPostStart = postStart;
            int newLeftPostEnd  = postStart + leftSize - 1;

            // 右子树
            int newRightPostStart = postStart + leftSize;
            int newRightPostEnd = postEnd - 1;

递归代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {

    private Map<Integer, Integer> valueToIdx = new HashMap<>();

    public TreeNode buildTree(int[] inorder, int inStart, int inEnd,
                            int[] postorder, int postStart, int postEnd){

            
            if(inStart > inEnd) {
                return null;
            }                    

            // 1. 获取根节点的值
            int rootVal = postorder[postEnd];
            // 2. 获取根节点在中序的下标
            int rootValIndex = valueToIdx.get(rootVal);

            // 计算左子树的大小
            // [1,2, {3}, 4,5,6]
            // 中值是 3 : leftSize = 2 - 0 = 2
            // rightSize = 5 - 2 = 3
            int leftSize = rootValIndex - inStart;
            
            // 新的中序开始/结束下标
            // 左子树
            int newLeftInStart = inStart;
            int newLeftInEnd = rootValIndex - 1;
            // 右子树
            int newRightInStart = rootValIndex + 1;
            int newRightInEnd = inEnd;

            // 新的后序开始/结束下标
            // 左子树
            int newLeftPostStart = postStart;
            int newLeftPostEnd  = postStart + leftSize - 1;

            // 右子树
            int newRightPostStart = postStart + leftSize;
            int newRightPostEnd = postEnd - 1;


            TreeNode root = new TreeNode(rootVal);

            root.left = buildTree(
                inorder, newLeftInStart, newLeftInEnd,
                postorder, newLeftPostStart, newLeftPostEnd
            );
            root.right = buildTree(
                inorder, newRightInStart, newRightInEnd,
                postorder, newRightPostStart, newRightPostEnd
            );

            return root;

    }

    public TreeNode buildTree(int[] inorder, int[] postorder) {

        for(int i = 0 ; i < inorder.length ; i++) {
            valueToIdx.put(inorder[i], i);
        }

        return buildTree(
            inorder, 0, inorder.length - 1,
            postorder, 0, postorder.length - 1
        );
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

兀坐晴窗独饮茶

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值