一、题目
1、算法题目
“给定两个整数数组ino和pos,其中ino是二叉树的中序遍历,pos是二叉树的后序遍历,请你构造并返回这颗二叉树。”
题目链接:
来源:力扣(LeetCode)
链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode) (leetcode-cn.com)
2、题目描述
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
代码语言:javascript复制示例 1:
输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]
代码语言:javascript复制示例 2:
输入: inorder = [-1], postorder = [-1]
输出: [-1]
二、解题
1、思路分析
先来了解一下什么是中序遍历和后序遍历:
- 中序遍历的顺序是先遍历左子树,再遍历根节点,最后遍历右子树
- 后序遍历的顺序是先遍历左子树,再遍历右子树,最后遍历根节点
根据中序遍历和后序遍历的性质,我们可以知道后序遍历的数组最后一个元素就是根节点。
根据这个性质,我们可以使用根节点的信息在中序遍历的数组中找到根节点所在的下标。
然后根据其在中序遍历的数组分成左右两部分,就是左右子树,然后同样的方法递归递归构造下去。
2、代码实现
代码参考:
代码语言:javascript复制class Solution {
int post_idx;
int[] postorder;
int[] inorder;
Map<Integer, Integer> idx_map = new HashMap<Integer, Integer>();
public TreeNode helper(int in_left, int in_right) {
// 如果这里没有节点构造二叉树了,就结束
if (in_left > in_right) {
return null;
}
// 选择 post_idx 位置的元素作为当前子树根节点
int root_val = postorder[post_idx];
TreeNode root = new TreeNode(root_val);
// 根据 root 所在位置分成左右两棵子树
int index = idx_map.get(root_val);
// 下标减一
post_idx--;
// 构造右子树
root.right = helper(index 1, in_right);
// 构造左子树
root.left = helper(in_left, index - 1);
return root;
}
public TreeNode buildTree(int[] inorder, int[] postorder) {
this.postorder = postorder;
this.inorder = inorder;
// 从后序遍历的最后一个元素开始
post_idx = postorder.length - 1;
// 建立(元素,下标)键值对的哈希表
int idx = 0;
for (Integer val : inorder) {
idx_map.put(val, idx );
}
return helper(0, inorder.length - 1);
}
}
3、时间复杂度
时间复杂度 : O(n)
其中n是树中的节点个数。
空间复杂度: O(n)
其中n是树中的节点个数。
三、总结
为了高效地查找根节点元素在中序表遍历数组中的下标,我们可以使用哈希表来存储中序序列。
在递归的过程中,利用哈希表(1)的时间复杂度查询当前根节点在中序遍历中的下标。
根绝后序遍历性质,递归创建右子树和左子树,创建左右子树的依赖关系,再存储右子树的节点,最后存储根节点。
返回根节点root。