1. 法一:递归
解题思路:时间复杂度O(n),空间复杂度O(n),空间使用了一个Map,大小为中心遍历的长度,以及递归需要的栈空间 |
---|
- 因为后序遍历[9,15,7,20,3]是左右中,它表示一个区间中,最后一个结点,是中间结点。比如[9,15,7,20,3]这个区间,正好是整个二叉树,共5个结点。那么这个区间的中间结点,也就是根节点为最后一个结点3.
- 而中序遍历[9,3,15,20,7]是左中右,它表示,只要找到中间结点,就可以分出左右两个区间来,比如[9,3,15,20,7]这个区间,已知3是根节点,那么[9]在其左子树,[15,20,7]在其右子树
- 所以思路很简单,我们先通过后序遍历序列,在区间中拿到最后一个结点,从而获取中间结点。然后通过中序遍历序列,获得其左右两个区间
- 然后其左右两个区间,因为后序遍历是左右中,中确定后,先确定右区间。
继续从后序遍历序列中,获取其最后一个结点20,20就是这个右子树的中间结点。
- 然后构造其左区间。依次类推,直到整颗二叉树完成构造。
后序遍历序列只需要从后往前依次遍历即可,因为只需要你做一遍后序遍历,就会发现,后序遍历的效果就是每一个中间结点,都按顺序排列在序列末尾
- 比如[9,15,7,20,3],根节点为3,3的右子树为20,20的右子树为7,此时通过中序遍历发现右边到头了
- 开始左子树构造,20的左子树为15, 然后15到头了。回到3 , 最后3的左子树为9. 9也到头了,没有结点了,构造完成
所以一定要注意,拿到中间结点后,先去右区间,右区间遍历完成后,再去左区间
class Solution {
int post_idx;
int[] postorder;
int[] inorder;
Map<Integer, Integer> idx_map = new HashMap<Integer, Integer>();
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);
}
public TreeNode helper(int in_left, int in_right) {
if (in_left > in_right) {
return null;
}
int root_val = postorder[post_idx];
TreeNode root = new TreeNode(root_val);
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;
}
}
2. 法二:迭代
思路分析:时间复杂度O(n),空间复杂度O(n),空间只用了队列来模拟递归的栈,无需map |
---|
- 将中序和后序都反过来:中序变为右中左,后序变成右左中
- 初始我们可以直接通过后序获取根结点root
- 而如果我们倒着遍历中序序列的话,正好获得到root的右区间
- 当我们发现倒着遍历中序,找到了root,那么剩下的是左区间的
- 然后重复这个过程即可
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (postorder == null || postorder.length == 0) {
return null;
}
TreeNode root = new TreeNode(postorder[postorder.length - 1]);
Deque<TreeNode> stack = new LinkedList<TreeNode>();
stack.push(root);
int inorderIndex = inorder.length - 1;
for (int i = postorder.length - 2; i >= 0; i--) {
int postorderVal = postorder[i];
TreeNode node = stack.peek();
if (node.val != inorder[inorderIndex]) {
node.right = new TreeNode(postorderVal);
stack.push(node.right);
} else {
while (!stack.isEmpty() && stack.peek().val == inorder[inorderIndex]) {
node = stack.pop();
inorderIndex--;
}
node.left = new TreeNode(postorderVal);
stack.push(node.left);
}
}
return root;
}
}