Skip to content

Commit 4e34407

Browse files
authored
feat: add solutions to lc problem: No.0889 (doocs#2355)
1 parent b9ad39b commit 4e34407

File tree

7 files changed

+431
-130
lines changed

7 files changed

+431
-130
lines changed

solution/0800-0899/0889.Construct Binary Tree from Preorder and Postorder Traversal/README.md

+152-45
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,27 @@
4646

4747
### 方法一:递归
4848

49-
1. 以 preorder 的第一个元素或 postorder 的最后一个元素为根节点的值。
50-
2. 以 preorder 的第二个元素作为左子树的根节点,在 postorder 中找到该元素的索引 i,然后基于索引 i 可以计算出左右子树的长度。
51-
3. 最后基于左右子树的长度,分别划分出前序和后序遍历序列中的左右子树,递归构造左右子树即可。
49+
前序遍历的顺序是:根节点 -> 左子树 -> 右子树,后序遍历的顺序是:左子树 -> 右子树 -> 根节点。
50+
51+
因此,二叉树的根节点一定是前序遍历的第一个节点,也是后序遍历的最后一个节点。
52+
53+
接下来,我们需要确定二叉树的左子树范围和右子树范围。
54+
55+
如果二叉树有左子树,那么左子树的根节点一定是前序遍历的第二个节点;如果二叉树没有左子树,那么前序遍历的第二个节点一定是右子树的根节点。由于这两种情况下,后序遍历的结果是一样的,因此,我们可以把前序遍历的第二个节点作为左子树的根节点,然后找到它在后序遍历中的位置,这样就确定了左子树的范围。
56+
57+
具体地,我们设计一个递归函数 $dfs(a, b, c, d)$,其中 $[a, b]$ 表示前序遍历的范围,而 $[c, d]$ 表示后序遍历的范围。这个函数的功能是根据前序遍历 $[a, b]$ 和后序遍历 $[c, d]$ 构造出二叉树的根节点。那么答案就是 $dfs(0, n - 1, 0, n - 1)$,其中 $n$ 是前序遍历的长度。
58+
59+
函数 $dfs(a, b, c, d)$ 的执行步骤如下:
60+
61+
1. 如果 $a > b$,说明范围为空,直接返回空节点。
62+
1. 否则,我们构造一个新的节点 $root$,它的值为前序遍历中的第一个节点的值,也就是 $preorder[a]$。
63+
1. 如果 $a$ 等于 $b$,说明 $root$ 没有左子树也没有右子树,直接返回 $root$。
64+
1. 否则,左子树的根节点的值为 $preorder[a + 1]$,我们在后序遍历中找到 $preorder[a + 1]$ 的位置,记为 $i$。那么左子树的节点个数 $m = i - c + 1$,由此可知左子树在前序遍历中的范围是 $[a + 1, a + m]$,后序遍历中的范围是 $[c, i]$,右子树在前序遍历中的范围是 $[a + m + 1, b]$,后序遍历中的范围是 $[i + 1, d - 1]$。
65+
1. 知道了左右子树的范围,我们就可以递归地重建左右子树,然后将左右子树的根节点分别作为 $root$ 的左右子节点。最后返回 $root$。
66+
67+
在函数 $dfs(a, b, c, d)$ 中,我们需要用到一个哈希表 $pos$,它存储了后序遍历中每个节点的位置。在函数的开头,我们可以先计算出这个哈希表,这样就可以在 $O(1)$ 的时间内找到任意节点在后序遍历中的位置。
68+
69+
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是节点数。
5270

5371
<!-- tabs:start -->
5472

@@ -62,22 +80,68 @@
6280
class Solution:
6381
def constructFromPrePost(
6482
self, preorder: List[int], postorder: List[int]
65-
) -> TreeNode:
66-
n = len(preorder)
67-
if n == 0:
68-
return None
69-
root = TreeNode(preorder[0])
70-
if n == 1:
71-
return root
72-
for i in range(n - 1):
73-
if postorder[i] == preorder[1]:
74-
root.left = self.constructFromPrePost(
75-
preorder[1 : 1 + i + 1], postorder[: i + 1]
76-
)
77-
root.right = self.constructFromPrePost(
78-
preorder[1 + i + 1 :], postorder[i + 1 : -1]
79-
)
83+
) -> Optional[TreeNode]:
84+
def dfs(a: int, b: int, c: int, d: int) -> Optional[TreeNode]:
85+
if a > b:
86+
return None
87+
root = TreeNode(preorder[a])
88+
if a == b:
8089
return root
90+
i = pos[preorder[a + 1]]
91+
m = i - c + 1
92+
root.left = dfs(a + 1, a + m, c, i)
93+
root.right = dfs(a + m + 1, b, i + 1, d - 1)
94+
return root
95+
96+
pos = {x: i for i, x in enumerate(postorder)}
97+
return dfs(0, len(preorder) - 1, 0, len(postorder) - 1)
98+
```
99+
100+
```java
101+
/**
102+
* Definition for a binary tree node.
103+
* public class TreeNode {
104+
* int val;
105+
* TreeNode left;
106+
* TreeNode right;
107+
* TreeNode() {}
108+
* TreeNode(int val) { this.val = val; }
109+
* TreeNode(int val, TreeNode left, TreeNode right) {
110+
* this.val = val;
111+
* this.left = left;
112+
* this.right = right;
113+
* }
114+
* }
115+
*/
116+
class Solution {
117+
private Map<Integer, Integer> pos = new HashMap<>();
118+
private int[] preorder;
119+
private int[] postorder;
120+
121+
public TreeNode constructFromPrePost(int[] preorder, int[] postorder) {
122+
this.preorder = preorder;
123+
this.postorder = postorder;
124+
for (int i = 0; i < postorder.length; ++i) {
125+
pos.put(postorder[i], i);
126+
}
127+
return dfs(0, preorder.length - 1, 0, postorder.length - 1);
128+
}
129+
130+
private TreeNode dfs(int a, int b, int c, int d) {
131+
if (a > b) {
132+
return null;
133+
}
134+
TreeNode root = new TreeNode(preorder[a]);
135+
if (a == b) {
136+
return root;
137+
}
138+
int i = pos.get(preorder[a + 1]);
139+
int m = i - c + 1;
140+
root.left = dfs(a + 1, a + m, c, i);
141+
root.right = dfs(a + m + 1, b, i + 1, d - 1);
142+
return root;
143+
}
144+
}
81145
```
82146

83147
```cpp
@@ -94,23 +158,27 @@ class Solution:
94158
*/
95159
class Solution {
96160
public:
97-
unordered_map<int, int> postMap;
98161
TreeNode* constructFromPrePost(vector<int>& preorder, vector<int>& postorder) {
99-
for (int i = 0; i < postorder.size(); i++) {
100-
postMap[postorder[i]] = i;
162+
unordered_map<int, int> pos;
163+
int n = postorder.size();
164+
for (int i = 0; i < n; ++i) {
165+
pos[postorder[i]] = i;
101166
}
102-
return build(preorder, 0, preorder.size() - 1, postorder, 0, postorder.size() - 1);
103-
}
104-
105-
TreeNode* build(vector<int>& preorder, int prel, int prer, vector<int>& postorder, int postl, int postr) {
106-
if (prel > prer) return nullptr;
107-
TreeNode* root = new TreeNode(preorder[prel]);
108-
if (prel == prer) return root;
109-
int leftRootIndex = postMap[preorder[prel + 1]];
110-
int leftLength = leftRootIndex - postl + 1;
111-
root->left = build(preorder, prel + 1, prel + leftLength, postorder, postl, leftRootIndex);
112-
root->right = build(preorder, prel + leftLength + 1, prer, postorder, leftRootIndex + 1, postr - 1);
113-
return root;
167+
function<TreeNode*(int, int, int, int)> dfs = [&](int a, int b, int c, int d) -> TreeNode* {
168+
if (a > b) {
169+
return nullptr;
170+
}
171+
TreeNode* root = new TreeNode(preorder[a]);
172+
if (a == b) {
173+
return root;
174+
}
175+
int i = pos[preorder[a + 1]];
176+
int m = i - c + 1;
177+
root->left = dfs(a + 1, a + m, c, i);
178+
root->right = dfs(a + m + 1, b, i + 1, d - 1);
179+
return root;
180+
};
181+
return dfs(0, n - 1, 0, n - 1);
114182
}
115183
};
116184
```
@@ -125,29 +193,68 @@ public:
125193
* }
126194
*/
127195
func constructFromPrePost(preorder []int, postorder []int) *TreeNode {
128-
postMap := make(map[int]int)
129-
for index, v := range postorder {
130-
postMap[v] = index
196+
pos := map[int]int{}
197+
for i, x := range postorder {
198+
pos[x] = i
131199
}
132-
var dfs func(prel, prer, postl, postr int) *TreeNode
133-
dfs = func(prel, prer, postl, postr int) *TreeNode {
134-
if prel > prer {
200+
var dfs func(int, int, int, int) *TreeNode
201+
dfs = func(a, b, c, d int) *TreeNode {
202+
if a > b {
135203
return nil
136204
}
137-
root := &TreeNode{Val: preorder[prel]}
138-
if prel == prer {
205+
root := &TreeNode{Val: preorder[a]}
206+
if a == b {
139207
return root
140208
}
141-
leftRootIndex := postMap[preorder[prel+1]]
142-
leftLength := leftRootIndex - postl + 1
143-
root.Left = dfs(prel+1, prel+leftLength, postl, leftRootIndex)
144-
root.Right = dfs(prel+leftLength+1, prer, leftRootIndex+1, postr-1)
209+
i := pos[preorder[a+1]]
210+
m := i - c + 1
211+
root.Left = dfs(a+1, a+m, c, i)
212+
root.Right = dfs(a+m+1, b, i+1, d-1)
145213
return root
146214
}
147215
return dfs(0, len(preorder)-1, 0, len(postorder)-1)
148216
}
149217
```
150218

219+
```ts
220+
/**
221+
* Definition for a binary tree node.
222+
* class TreeNode {
223+
* val: number
224+
* left: TreeNode | null
225+
* right: TreeNode | null
226+
* constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
227+
* this.val = (val===undefined ? 0 : val)
228+
* this.left = (left===undefined ? null : left)
229+
* this.right = (right===undefined ? null : right)
230+
* }
231+
* }
232+
*/
233+
234+
function constructFromPrePost(preorder: number[], postorder: number[]): TreeNode | null {
235+
const pos: Map<number, number> = new Map();
236+
const n = postorder.length;
237+
for (let i = 0; i < n; ++i) {
238+
pos.set(postorder[i], i);
239+
}
240+
const dfs = (a: number, b: number, c: number, d: number): TreeNode | null => {
241+
if (a > b) {
242+
return null;
243+
}
244+
const root = new TreeNode(preorder[a]);
245+
if (a === b) {
246+
return root;
247+
}
248+
const i = pos.get(preorder[a + 1])!;
249+
const m = i - c + 1;
250+
root.left = dfs(a + 1, a + m, c, i);
251+
root.right = dfs(a + m + 1, b, i + 1, d - 1);
252+
return root;
253+
};
254+
return dfs(0, n - 1, 0, n - 1);
255+
}
256+
```
257+
151258
<!-- tabs:end -->
152259

153260
<!-- end -->

0 commit comments

Comments
 (0)