首页 > 其他分享 >力扣105 根据先序遍历以及中序遍历构建二叉树

力扣105 根据先序遍历以及中序遍历构建二叉树

时间:2023-01-02 13:44:27浏览次数:43  
标签:遍历 中序 find 二叉树 l1 节点 先序

力扣105 根据先序遍历以及中序遍历构建二叉树

题目:

给定两个整数数组 preorderinorder ,其中 preorder 是二叉树的先序遍历inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例 1:

img

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]

解题思路:

先序遍历是“根左右”所以先序遍历数组中的第一个元素肯定是整棵树的根节点,中序遍历是“左根右”所以根节点将左子树的节点元素与右子树的节点元素分隔开来。我们首先确定整棵树的根节点head然后在中序遍历中找到根节点的位置find然后在先序遍历数组中根据find划出左子树节点元素的范围以及右子树节点元素的范围然后再递归地构建树。

代码:

/**
 * 根据一棵树的先序遍历和中序遍历构建一棵树
 * 首先我们应该根据先序遍历确定这棵树的根节点然后在中序遍历中找到这棵树的根节点
 * 然后将中序遍历分为左右两部分,再根据这两部分所占的数量在先序遍历中确定左子树和右子树的部分
 * 依次类推做递归最后确定这棵树
 */
public class BasePreAndInBuildTree {
    //1.先定义一个二叉树的节点类
    public static class TreeNode{
        public int value;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(int value) {
            this.value = value;
        }
    }

    //2.定义根据先序遍历以及中序遍历构建二叉树的方法
    public static TreeNode buildTree1(int[] pre,int[] in){
        //2.1如果先序遍历为空或者中序遍历为空或者先序遍历数组的长度与中序遍历数组的长度不相等返回null
        if(pre == null || in == null || pre.length != in.length){
            return null;
        }
        return basePreAndInBuildTree(pre,0,pre.length-1,in,0,in.length-1);
    }
    /*
      3.有一棵树先序遍历是pre[l1...r1]中序遍历是in[l2...r2]
      根据这棵树的先序遍历以及中序遍历构建一棵树
    */
    public static TreeNode basePreAndInBuildTree(int[] pre,int l1,int r1,int[] in,int l2,int r2){
        if(l1 > r1){
            return null;
        }
        //3.2在先序遍历的数组pre中取出根节点
        TreeNode head = new TreeNode(pre[l1]);
        //3.3如果先序遍历数组的第一个元素与中序遍历数组的第一个元素相等说明此树没有左子树
        if(l1 == r1){
            return head;
        }
        //3.4在中序遍历数组中寻找根节点的位置
        int find = l2;
        while (in[find] != pre[l1]){
            find++;
        }
        //3.5递归地构建左子树,递归地构建右子树
        /*
        根据上一步我们找到了在中序遍历中根节点的位置find所以左子树节点的个数为find-l2所以在先序遍历数组中左子树节点的元素处于l1+1 到 l1+find-l2
        在中序遍历数组in中左子树节点的元素处于l2 到 find-1
         */
        head.left = basePreAndInBuildTree(pre,l1+1,l1+find-l2,in,l2,find-1);
        /*
        根据3.4我们找到了在中序遍历中根节点的位置find 且根据上一步知道左子树节点元素的右边界点为 l1+find-l2所以在先序遍历数组中 右子树节点的元素处于
        l1+find-l2+1 到 r1 在中序遍历数组in中右子树节点元素的位置处于 find+1 到 r2
         */
        head.right = basePreAndInBuildTree(pre,l1+find-l2+1,r1,in,find+1,r2);
        //3.6最后返回创建好树的根节点
        return head;
    }
}

优化:

因为上面地方法每次在中序遍历数组中寻找根节点地位置的时候每次都需要遍历 效率不高,我们可以考虑将中序遍历数组放在一个map中将数组值作为key数组元素的下标作为value

代码:

/**
     * 优化:上面每一次都需要遍历中序遍历数组找到根节点效率不高
     * 我们可以将中序遍历数组存到一张表(map)中,值为key数组位置value
     */
    //2.定义根据先序遍历以及中序遍历构建二叉树的方法
    public static TreeNode buildTree2(int[] pre, int[] in) {
        //2.1如果先序遍历为空或者中序遍历为空或者先序遍历数组的长度与中序遍历数组的长度不相等返回null
        if (pre == null || in == null || pre.length != in.length) {
            return null;
        }
        //2.2定义一个hashmap将中序遍历数组中元素放进map中 值作为key 数组下标作为value
        HashMap<Integer, Integer> valueIndexMap = new HashMap<>();
        for (int i = 0; i < in.length; i++) {
            valueIndexMap.put(in[i], i);
        }
        return basePreAndInBuildTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
    }

    /*
      3.有一棵树先序遍历是pre[l1...r1]中序遍历是in[l2...r2]
      根据这棵树的先序遍历以及中序遍历构建一棵树
    */
    public static TreeNode basePreAndInBuildTree(int[] pre, int l1, int r1, int[] in, int l2, int r2, HashMap<Integer, Integer> valueIndexMap) {
        if (l1 > r1) {
            return null;
        }
        //3.2在先序遍历的数组pre中取出根节点
        TreeNode head = new TreeNode(pre[l1]);
        //3.3如果先序遍历数组的第一个元素与中序遍历数组的第一个元素相等说明此树没有左子树
        if (l1 == r1) {
            return head;
        }
        //3.4在valueIndexMap中寻找根节点的位置
        int find = valueIndexMap.get(pre[l1]);
        //3.5递归地构建左子树,递归地构建右子树
        /*
        根据上一步我们找到了在中序遍历中根节点的位置find所以左子树节点的个数为find-l2所以在先序遍历数组中左子树节点的元素处于l1+1 到 l1+find-l2
        在中序遍历数组in中左子树节点的元素处于l2 到 find-1
         */
        head.left = basePreAndInBuildTree(pre, l1 + 1, l1 + find - l2, in, l2, find - 1);
        /*
        根据3.4我们找到了在中序遍历中根节点的位置find 且根据上一步知道左子树节点元素的右边界点为 l1+find-l2所以在先序遍历数组中 右子树节点的元素处于
        l1+find-l2+1 到 r1 在中序遍历数组in中右子树节点元素的位置处于 find+1 到 r2
         */
        head.right = basePreAndInBuildTree(pre, l1 + find - l2 + 1, r1, in, find + 1, r2);
        //3.6最后返回创建好树的根节点
        return head;
    }

标签:遍历,中序,find,二叉树,l1,节点,先序
From: https://www.cnblogs.com/ygstudy/p/17019328.html

相关文章

  • 力扣104 求二叉树的最大深度
    力扣104求二叉树的最大深度题目:给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明:叶子节点是指没有子节点的节点。示......
  • BM27 按之字形顺序打印二叉树
    题目描述思路分析这题在上一道层序遍历的基础上会更加方便。我们之前就可以得到每一层的数据,此时只是对每一层的遍历顺序做相应的处理即可注意:1.我们在向tempQueue......
  • java中的HashMap类的遍历
    示例代码如下:1publicclassHashMapBianLiTest{2publicstaticvoidmain(String[]args){3//hashMap的遍历4HashMaphashMap=new......
  • BM26 求二叉树的层序遍历
    题目描述思路分析外部使用一个容器来存储,借助一个临时的栈来存储每一层的节点,之后根绝临时栈不为空的条件来遍历每一层,并将结果存到容器中代码参考constlevelOrder=......
  • Set接口实现类的遍历
    Set接口实现类主要是:HashSet,LinkedHashSet【二者,可以看看java集合.xmind文件】,TreeSet【没有学到】一.HashSet类的遍历:1publicclassSetBianLiTest{2pu......
  • 二叉树的先中后序遍历
    二叉树:每个节点最多只有两个字节点JS中通常用Object来模拟二叉树(val:1,left:0,right:0)constbt={val:1,left:{......
  • List接口实现类的遍历方式
    List接口实现类主要有:ArrayList,LinkedList,Vector【三者区别,可以看看java集合.xmind文件】一.ArrayList类的遍历:1publicclassListBianLiTest{2publics......
  • P3916 图的遍历
    题目描述给出 NN 个点,MM 条边的有向图,对于每个点 vv,求 A(v)A(v) 表示从点 vv 出发,能到达的编号最大的点。输入格式第 11 行 22 个整数 N,MN,M,表示点数......
  • leetcode-590. N 叉树的后序遍历
    590.N叉树的后序遍历-力扣(Leetcode)可以参考[[leetcode-589.N叉树的前序遍历]],代码差不多/***DefinitionforaNode.*typeNodestruct{*Valint......
  • leetcode-589. N 叉树的前序遍历
    589.N叉树的前序遍历-力扣(Leetcode)Go语言的切片操作方便性还不错/***DefinitionforaNode.*typeNodestruct{*Valint*Children[]*Node*......