• 分别从中序、后续中组成二叉树(likou106)


    likou106本题会给你两个数组,arr1由中序遍历,arr2用后续遍历,返回一个原始二叉树。

    首先我们要理解好三种遍历方式的顺序:

    (25条消息) 二叉树的理论知识_小肖在路上的博客-CSDN博客

    然后再回到这个题:

    创建二叉树唯一的方法就是,创建根节点,然后创建左右节点连接上。

    所以我们在解题中必须创建根节点,所以就得找到根节点在哪里。 

    寻找根节点:

    arr2既然是后续遍历,arr2数组的最后一个元素,肯定是一个根节点,并且是最上层的根节点。所以我们每次都是找到arr2的最后一个元素作为根节点。然后递归创建左右节点。

     寻找左右节点:

     arr1是中序遍历,就说明它的根节点左边就是左节点,右边就是右节点。

    所以我们每次寻找到根节点后,就可以在arr1中找到该节点的左右节点。

     

    1. package lqb;
    2. import java.util.HashMap;
    3. import java.util.Map;
    4. import shuJuJieGouYuSuanFa.erChaShu.*;
    5. public class likou106 {
    6. public static void main(String[] args) {
    7. TreeNode root = new likou106().buildTree(new int[]{9, 3, 15, 20, 7}, new int[]{9, 15, 7, 20, 3});
    8. f1(root);
    9. }
    10. private static void f1(TreeNode root) {
    11. if (root == null) {
    12. return;
    13. }
    14. System.out.println(root.val);
    15. f1(root.left);
    16. f1(root.right);
    17. }
    18. Map map = new HashMap<>();
    19. public TreeNode buildTree(int[] arr1, int[] arr2) {
    20. for (int i = 0; i < arr1.length; i++) {
    21. map.put(arr1[i], i);
    22. }
    23. return dfs(arr1, 0, arr1.length, arr2, 0, arr2.length);
    24. }
    25. private TreeNode dfs(int[] arr1, int arr1Kai, int arr1Lan, int[] arr2, int arr2Kai, int arr2Lan) {
    26. if (arr1Lan <= arr1Kai || arr2Lan <= arr2Kai) {
    27. return null;
    28. }
    29. int t = map.get(arr2[arr2Lan - 1]);
    30. TreeNode root = new TreeNode(arr1[t]);
    31. int indexLen = t - arr1Kai;
    32. root.left = dfs(arr1, arr1Kai, t, arr2, arr2Kai, arr2Kai + indexLen);
    33. root.right = dfs(arr1, t + 1, arr1Lan, arr2, arr2Kai + indexLen, arr2Lan - 1);
    34. return root;
    35. }
    36. }

    既然数组开始下标与结束下标重合,就说明已经没有节点可以使用了。直接返回null,作为所谓的空叶子节点

    1. if (arr1Lan <= arr1Kai || arr2Lan <= arr2Kai) {
    2. return null;
    3. }

    然后这里会运用到一个哈希表

    快速寻找某个值的出现个数、位置。

    我们要第一时间想到哈希表

    既然要在arr1中寻找根节点对应的左右节点。我们就直接将arr1的数据、下标存入map中,快速寻找到下标。 记得将map成员化

     

    1. for (int i = 0; i < arr1.length; i++) {
    2. map.put(arr1[i], i);
    3. }

    然后就是寻找根节点:arr2的最后一个数据所对应在arr1的下标,它的左边就是该根节点的左节点,右边就是右节点

     int t = map.get(arr2[arr2Lan - 1]);

    现在分别创建根节点:

       TreeNode root = new TreeNode(arr1[t]);
           

    然后记录根节点的左节点个数:t为根节点的下标,t的左边所有元素都是左节点,

    所以直接【t-arr1开始下标】,因为下一次递归,这一段区间又是一个完整的二叉树,也有左右节点。

     int indexLen = t - arr1Kai;

    现在将左右节点赋值:也就是递归求左右节点(求子二叉树)

    在这里我们得清楚,递归的参数含义:

     private TreeNode dfs(int[] arr1, int arr1Kai, int arr1Lan, int[] arr2, int arr2Kai, int arr2Lan) 

    arr1:中序遍历的数组

    arr1Kai:中序遍历数组的开始下标

    arr1Lan:中序遍历数组的结束下标。

    arr2:后续数组

    arr2Kai:后续数组的开始下标。

    arr2Lan:后续数组的结束下标。

    我也是在写这篇博客的时候才真正理解到,这里为什么要怎么做、

    我们通过赋值根节点的左右节点进行递归,就把两个数组分成可四个部分,分别是:

    由根节点划分的arr1的左节点,arr1的右节点

    再通过根节点的划分,得到arr2的左节点和右节点。

    arr1的左节点则是直接【开始节点,t】arr1的右节点【t+1,arr1结束

    arr2的左节点是【开始节点,开始节点+t】右节点是【开始节点+t,arr2结束节点

    进行左右节点赋值的时候,将四个切割数组传入,达到赋值的目的。

    1. root.left = dfs(arr1, arr1Kai, t, arr2, arr2Kai, arr2Kai + indexLen);
    2. root.right = dfs(arr1, t + 1, arr1Lan, arr2, arr2Kai + indexLen, arr2Lan - 1);

     各位一定要仔细思考代码的逻辑,不说了,我再去想半小时。。。

  • 相关阅读:
    Shell编程之条件语句
    c++中的内存分区模型
    (二十三)数据结构-交换排序
    2020-java中级面试题
    SQLAchemy 常用操作
    MFC学生成绩管理系统
    【玩机】如何修改iPhone充电提示音!最详细简单保姆级教程~ 学费了可替换任意音频做你的专属充电提示音!——后厂村路灯
    Java面向对象程序设计综合练习1(编程题)
    XML语法、约束
    HTML网页期末作业:基于Html+Css+javascript的网页制作(化妆品企业官网设计20页)
  • 原文地址:https://blog.csdn.net/qx020814/article/details/127457938