剑指offer - 重建二叉树(Java实现)

题目连接:https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=13&&tqId=11157&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

  • 下面首先我们呢来介绍如何根据二叉树的前序遍历和中序遍历来确定一颗二叉树。

前序遍历:[1,2,4,7,3,5,6,8]
中序遍历:[4,7,2,1,5,3,8,6]

  我们知道,前序遍历是先输出根结点,所以在一个数组中,出现的第一个数字必然是这个二叉树的根结点。对于一颗二叉树来说在进行中序遍历时,只有左子树上面所有的点按照中序遍历的规则都遍历结束了我们才输出根结点,然后在中序遍历其右子树上上面的所有点。所以对于中序遍历得到的数组来说,对于某一个位置的数值,其左边的数字都属于这棵树的左子树上面的点,其右边的数字都属于其右子树上面的点。如果我们知道了某一颗树的根节点,又知道其左右子树,那么我们就可以唯一的确定一颗二叉树。

  • 图解重建二叉树

图解重建二叉树
  看图我们可以发现,前序遍历得到的数组的第一个数字就是当前树的根节点,我们在中序遍历的数组中找到这个根结点,这个根节点的左边属于这棵树的左子树,右边属于这棵树的右子树,一直重复这样的过程就可以构造一颗二叉树出来。
  综上所述,我们可以使用递归的方式来构建这颗二叉树,以中序遍历的第一个值作为当前树的根结点,然后处理出左边的中序遍历结果,以及前序遍历结果,向左递归以同样的方式算下面的子树的情况。右边则使用同样的方式处理。如果最后我们得到了空的中序遍历结果或者空的前序遍历结果,说明我们到达了叶子节点的最后一层,此时我们就可以将这个条件作为递归的出口。

  思路一:自己编写函数来构建出新的中序遍历和前序遍历将结果,然后在这个基础上进行相关的判断与递归。

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        return build(pre, 0, pre.length - 1, in, 0, in.length - 1); //构建新的中序和前序遍历结果
    }
    TreeNode build(int[] pre, int preLeft, int preRight, int[] vin, int vinLeft, int vinRight) {
        if(preLeft > preRight || vinLeft > vinRight) return null;
        TreeNode root = new TreeNode(pre[preLeft]);
        for(int i = vinLeft; i <= vinRight; ++ i) {
            if(vin[i] == pre[preLeft]) {//中序遍历找到根结点
                root.left = build(pre, preLeft + 1, preRight + i - vinRight, vin, vinLeft, i - 1);//左边归左子树
                root.right = build(pre, preLeft + i - vinLeft + 1, preRight, vin, i + 1, vinRight);//右边归右子树
            }
        }
        return root;
    }
}

  思路二:使用库函数来构建新的中序和前序遍历结果,Arrays.copyOfRange(pre, s, e)表示将pre数组中的[s, e)位置的结果复制到一个新的数组中去。使用时需要导入 import java.util.*

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
import java.util.*;

public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        int len1 = pre.length, len2 = in.length;
        if(len1 == 0 || len2 == 0) { //数组为空说明到了叶子节点的下一层
            return null;
        }
        TreeNode root = new TreeNode(pre[0]);
        for(int i = 0; i < len2; ++ i) {
            if(in[i] == pre[0]) {
                root.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i + 1), Arrays.copyOfRange(in, 0, i));//左子树前序和中序结果
                root.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1, len1), Arrays.copyOfRange(in, i + 1, len2));//右子树前序和中序结果
            }
        }
        return root;
    }
}
【剑指offer】题目全解 文章被收录于专栏

本专栏主要是刷剑指offer的题解记录

全部评论

相关推荐

HR_丸山彩同学:你的项目描述里,系统设计讲了很多:MemCube是什么、三级存储架构怎么设计、四种遗忘策略分别是什么。这些面试的时候讲没问题,但简历上不需要这么细。 简历要突出的是影响力,不是实现细节。面试官看简历的时候想知道的是「这个项目有多大价值」,不是「这个项目具体怎么实现的」。实现细节是面试时候聊的 怎么改:技术细节可以精简为一句「采用三级存储架构+四种遗忘策略」,把省出来的篇幅用来写影响力。比如:项目有没有开源?有没有写成技术博客?有没有被别人使用过? 校园经历没有任何信息量,任何人都可以写这句话,写了等于没写。更关键的是,你投的是技术岗,校园活动经历本来就不是加分项。如果非要写,必须写出具体的数字和成果。如果你没有这些数字,那就老老实实删掉 「端到端耗时缩减30-40%」要给出确切数字和绝对值。从1000ms降到600ms是降了40%,从100ms降到60ms也是降了40%,但这两个含义完全不一样。其他也是,涉及到数据,准备好证据,口径统一,面试会问 「熟练」「熟悉」「了解」混在一起用,读起来很乱。而且「了解前端需求」最好改成「具备前后端协作经验」
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务