草庐IT

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

PersistentYg 2023-03-28 原文

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

题目:

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

示例 1:

输入: 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;
    }

有关力扣105 根据先序遍历以及中序遍历构建二叉树的更多相关文章

  1. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  2. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  3. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  4. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  5. 阿里云国际版免费试用:如何注册以及注意事项 - 2

    作为新的阿里云用户,您可以50免费试用多种优惠,价值高达1,700美元(或8,500美元)。这将让您了解和体验阿里云平台上提供的一系列产品和服务。如果您以个人身份注册免费试用,您将获得价值1,700美元的优惠。但是,如果您是注册公司,您可以选择企业免费试用,提交基本信息通过企业实名注册验证,即可开始价值$8,500的免费试用!本教程介绍了如何设置您的帐户并使用您的免费试用版。​关于免费试用在我们开始此试用之前,您还必须遵守以下条款和条件才能访问您的免费试用:只有在一年内创建的账户才有资格获得阿里云免费试用。通过此免费试用优惠,用户可以免费试用免费试用活动页面上列出的每种产品一次。如果您有多个帐

  6. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  7. ruby - Chef Ruby 遍历 .erb 模板文件中的属性 - 2

    所以这可能有点令人困惑,但请耐心等待。简而言之,我想遍历具有特定键值的所有属性,然后如果值不为空,则将它们插入到模板中。这是我的代码:属性:#===DefaultfileConfigurations#default['elasticsearch']['default']['ES_USER']=''default['elasticsearch']['default']['ES_GROUP']=''default['elasticsearch']['default']['ES_HEAP_SIZE']=''default['elasticsearch']['default']['MAX_OP

  8. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  9. ruby - 如何根据长度将路径数组转换为嵌套数组或散列 - 2

    我需要根据字符串路径的长度将字符串路径数组转换为符号、哈希和数组的数组给定以下数组:array=["info","services","about/company","about/history/part1","about/history/part2"]我想生成以下输出,对不同级别进行分组,根据级别的结构混合使用符号和对象。产生以下输出:[:info,:services,about:[:company,history:[:part1,:part2]]]#altsyntax[:info,:services,{:about=>[:company,{:history=>[:part1,:pa

  10. ruby - 如何遍历 Ruby 中所有正则表达式匹配的字符串? - 2

    我们有一个字符串:“”这个正则表达式://i如何从当前字符串中获取所有匹配项? 最佳答案 "".scan(//)参见scan在ruby​​-docs上 关于ruby-如何遍历Ruby中所有正则表达式匹配的字符串?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/6857852/

随机推荐