likou106本题会给你两个数组,arr1由中序遍历,arr2用后续遍历,返回一个原始二叉树。
首先我们要理解好三种遍历方式的顺序:
(25条消息) 二叉树的理论知识_小肖在路上的博客-CSDN博客
然后再回到这个题:
创建二叉树唯一的方法就是,创建根节点,然后创建左右节点连接上。
所以我们在解题中必须创建根节点,所以就得找到根节点在哪里。
寻找根节点:
arr2既然是后续遍历,arr2数组的最后一个元素,肯定是一个根节点,并且是最上层的根节点。所以我们每次都是找到arr2的最后一个元素作为根节点。然后递归创建左右节点。
寻找左右节点:
arr1是中序遍历,就说明它的根节点左边就是左节点,右边就是右节点。
所以我们每次寻找到根节点后,就可以在arr1中找到该节点的左右节点。
package lqb;import java.util.HashMap;
import java.util.Map;import shuJuJieGouYuSuanFa.erChaShu.*;public class likou106 {public static void main(String[] args) {TreeNode root = new likou106().buildTree(new int[]{9, 3, 15, 20, 7}, new int[]{9, 15, 7, 20, 3});f1(root);}private static void f1(TreeNode root) {if (root == null) {return;}System.out.println(root.val);f1(root.left);f1(root.right);}Map<Integer, Integer> map = new HashMap<>();public TreeNode buildTree(int[] arr1, int[] arr2) {for (int i = 0; i < arr1.length; i++) {map.put(arr1[i], i);}return dfs(arr1, 0, arr1.length, arr2, 0, arr2.length);}private TreeNode dfs(int[] arr1, int arr1Kai, int arr1Lan, int[] arr2, int arr2Kai, int arr2Lan) {if (arr1Lan <= arr1Kai || arr2Lan <= arr2Kai) {return null;}int t = map.get(arr2[arr2Lan - 1]);TreeNode root = new TreeNode(arr1[t]);int indexLen = t - arr1Kai;root.left = dfs(arr1, arr1Kai, t, arr2, arr2Kai, arr2Kai + indexLen);root.right = dfs(arr1, t + 1, arr1Lan, arr2, arr2Kai + indexLen, arr2Lan - 1);return root;}
}
既然数组开始下标与结束下标重合,就说明已经没有节点可以使用了。直接返回null,作为所谓的空叶子节点
if (arr1Lan <= arr1Kai || arr2Lan <= arr2Kai) {return null;}
然后这里会运用到一个哈希表:
快速寻找某个值的出现个数、位置。
我们要第一时间想到哈希表
既然要在arr1中寻找根节点对应的左右节点。我们就直接将arr1的数据、下标存入map中,快速寻找到下标。 记得将map成员化
for (int i = 0; i < arr1.length; i++) {map.put(arr1[i], i);}
然后就是寻找根节点: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结束节点】
进行左右节点赋值的时候,将四个切割数组传入,达到赋值的目的。
root.left = dfs(arr1, arr1Kai, t, arr2, arr2Kai, arr2Kai + indexLen);root.right = dfs(arr1, t + 1, arr1Lan, arr2, arr2Kai + indexLen, arr2Lan - 1);
各位一定要仔细思考代码的逻辑,不说了,我再去想半小时。。。