「这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战」
前言
力扣第106题 从中序与后序遍历序列构造二叉树
如下所示:
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
一、思路
题目意思很明确:利用中序和后序遍历还原二叉树。这一题昨天写的那一题非常的相似,思路也是差不多的,有兴趣的可以看一下# 力扣第105题-从前序与中序遍历序列构造二叉树
我们知道中序遍历和后序遍历有如下的特点:
- 中序遍历:先
左子树节点
,再根节点
,最后是右子树节点
- 后序遍历:先
左子树节点
,再右子树节点
,最后是根节点
如果问你二叉树的根节点是什么?你知道吗?
很显然二叉树的根节点就是 后序遍历
的最后一个元素了。那子树的根节点又是什么呢?这与当前子树的起始位置和节点数量有关了,不妨继续向下看以下图文分析。
图解算法
此处以实例中的 inorder = [9,3,15,20,7],postorder = [9,15,7,20,3]
作为例子,用表格画一下,就如下所示:
- 确定第一个根节点
root1
,很显然是后序遍历的最后一个节点
- 再在中序遍历中找到这个根节点的位置,确定出左子树
left1
和右子树right1
。如下图所示:
-
我们再确认左子树
left1
的根节点因为根节点
root1
在中序遍历中的位置是2
,说明右子树有3
个节点。所以left1
的根节点是root1
向前移动4
格的位置(要除去自身)
- 再确认右子树
right1
的根节点,只需要将root1
前移动1
格即可。(因为后续遍历是左右根,根节点前面就是右子树的最后一个节点,即右子树的根节点)
- 我们找到了所有的根节点,那么还原这个二叉树也就不是什么难事了。最终的结果如下图所示:
二、实现
实现代码
实现代码与思路中保持一致,为了避免多次在 中序遍历
中找目标值,所以先用 Map
存储了中序遍历所有的节点值和位置。
private Map<Integer, Integer> inMap;
public TreeNode buildTree(int[] inorder, int[] postorder) {
int n = inorder.length;
int m = postorder.length;
// 构造哈希映射,记住中序遍历中每个节点的位置
inMap = new HashMap<>();
for (int i=0; i<n; i++) {
inMap.put(inorder[i], i);
}
return dfs(postorder, 0, n-1, m-1);
}
/**
* @param postorder 后序遍历
* @param inLeft 中序遍历左子树起始位
* @param inRight 中序遍历右子树起始位
* @param postRoot 后续遍历中根节点的位置
* @return
*/
public TreeNode dfs(int[] postorder, int inLeft, int inRight, int postRoot) {
if (inLeft > inRight)
return null;
// 后序遍历中从后往前都是根节点
TreeNode root = new TreeNode(postorder[postRoot]);
int inorder_root = inMap.get(postorder[postRoot]);
root.left = dfs(postorder, inLeft, inorder_root-1, postRoot-(inRight-inorder_root)-1);
root.right = dfs(postorder, inorder_root+1, inRight, postRoot-1);
return root;
}
测试代码
public static void main(String[] args) {
int[] inorder = {9,3,15,20,7};
int[] postorder = {9,15,7,20,3};
TreeNode treeNode = new Number106().buildTree(inorder, postorder);
System.out.println("test");
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~