当前位置: 首页 > news >正文

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

中序后续构造二叉树

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

相关文章:

  • wordpress首页图片管理/seo排名诊断
  • 什么是网站镜像/百度网盘电脑版下载
  • v2ex wordpress/长沙seo代理
  • 郑州做网站的公司msgg/手机百度浏览器
  • wordpress如何添加封面/千牛怎么做免费推广引流
  • 做任务赚钱的网站有哪些/乔拓云智能建站官网
  • 设计模式_结构型模式 -《装饰器模式》
  • Git Extensions的安装与使用
  • ESP-IDF:基于企业链表实现的循环链表实例,实现了初始,插入,循环打印的功能
  • 【博客591】LVS的DR和NAT模式下要注意的缺陷
  • 优秀的程序员是如何做好时间管理的
  • idea中代码git的版本穿梭Git Rest三种模式详解(soft,mixed,hard)
  • 【北京理工大学-Python 数据分析-3.2Pandas数据特征分析】
  • (C++) 从stl算法的谓词 分析lambda表达式的本质
  • 机器学习的相关概念与建模流程
  • C语言文件操作(一)
  • 故障分析 | 库表名-大小写不规范,运维两行泪
  • 【JavaScript】对象