0889-根据前序和后序遍历构造二叉树

Raphael Liu Lv10

给定两个整数数组,preorderpostorder ,其中 preorder 是一个具有 无重复
值的二叉树的前序遍历,postorder 是同一棵树的后序遍历,重构并返回二叉树。

如果存在多个答案,您可以返回其中 任何 一个。

示例 1:

**输入:** preorder = [1,2,4,5,3,6,7], postorder = [4,5,2,6,7,3,1]
**输出:** [1,2,3,4,5,6,7]

示例 2:

**输入:** preorder = [1], postorder = [1]
**输出:** [1]

提示:

  • 1 <= preorder.length <= 30
  • 1 <= preorder[i] <= preorder.length
  • preorder 中所有值都 不同
  • postorder.length == preorder.length
  • 1 <= postorder[i] <= postorder.length
  • postorder 中所有值都 不同
  • 保证 preorderpostorder 是同一棵二叉树的前序遍历和后序遍历

方法一:递归

思路

前序遍历为:

  • (根结点) (前序遍历左分支) (前序遍历右分支)

而后序遍历为:

  • (后序遍历左分支) (后序遍历右分支) (根结点)

例如,如果最终的二叉树可以被序列化的表述为 [1, 2, 3, 4, 5, 6, 7],那么其前序遍历为 [1] + [2, 4, 5] + [3, 6, 7],而后序遍历为 [4, 5, 2] + [6, 7, 3] + [1].

如果我们知道左分支有多少个结点,我们就可以对这些数组进行分组,并用递归生成树的每个分支。

算法

我们令左分支有 L 个节点。我们知道左分支的头节点为 pre[1],但它也出现在左分支的后序表示的最后。所以 pre[1] = post[L-1](因为结点的值具有唯一性),因此 L = post.indexOf(pre[1]) + 1

现在在我们的递归步骤中,左分支由 pre[1 : L+1]post[0 : L] 重新分支,而右分支将由 pre[L+1 : N]post[L : N-1] 重新分支。

[FhBbdzey-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public TreeNode constructFromPrePost(int[] pre, int[] post) {
int N = pre.length;
if (N == 0) return null;
TreeNode root = new TreeNode(pre[0]);
if (N == 1) return root;

int L = 0;
for (int i = 0; i < N; ++i)
if (post[i] == pre[1])
L = i+1;

root.left = constructFromPrePost(Arrays.copyOfRange(pre, 1, L+1),
Arrays.copyOfRange(post, 0, L));
root.right = constructFromPrePost(Arrays.copyOfRange(pre, L+1, N),
Arrays.copyOfRange(post, L, N-1));
return root;
}
}
[FhBbdzey-Python]
1
2
3
4
5
6
7
8
9
10
class Solution(object):
def constructFromPrePost(self, pre, post):
if not pre: return None
root = TreeNode(pre[0])
if len(pre) == 1: return root

L = post.index(pre[1]) + 1
root.left = self.constructFromPrePost(pre[1:L+1], post[:L])
root.right = self.constructFromPrePost(pre[L+1:], post[L:-1])
return root

复杂度分析

  • 时间复杂度:O(N^2),其中 N 是结点的数量。
  • 空间复杂度:O(N^2)。

方法二:递归(节约空间的变体)

说明

我们这里提出一个方法一的变体,使用索引指代子数组 prepost,而不是通过那些子数组的副本。这里,(i0, i1, N) 指的是 pre[i0:i0+N], post[i1:i1+N].

[fsN6ns47-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
int[] pre, post;
public TreeNode constructFromPrePost(int[] pre, int[] post) {
this.pre = pre;
this.post = post;
return make(0, 0, pre.length);
}

public TreeNode make(int i0, int i1, int N) {
if (N == 0) return null;
TreeNode root = new TreeNode(pre[i0]);
if (N == 1) return root;

int L = 1;
for (; L < N; ++L)
if (post[i1 + L-1] == pre[i0 + 1])
break;

root.left = make(i0+1, i1, L);
root.right = make(i0+L+1, i1+L, N-1-L);
return root;
}
}
[fsN6ns47-Python]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution(object):
def constructFromPrePost(self, pre, post):
def make(i0, i1, N):
if N == 0: return None
root = TreeNode(pre[i0])
if N == 1: return root

for L in xrange(N):
if post[i1 + L - 1] == pre[i0 + 1]:
break

root.left = make(i0 + 1, i1, L)
root.right = make(i0 + L + 1, i1 + L, N - 1 - L)
return root

return make(0, 0, len(pre))

复杂度分析

  • 时间复杂度:O(N^2),其中 N 是结点的数目。

  • 空间复杂度:O(N),答案所用去的空间。

 Comments
On this page
0889-根据前序和后序遍历构造二叉树