|
| 1 | +# [2764. is Array a Preorder of Some Binary Tree](https://leetcode.cn/problems/is-array-a-preorder-of-some-binary-tree) |
| 2 | + |
| 3 | +[English Version](/solution/2700-2799/2764.is%20Array%20a%20Preorder%20of%20Some%20%E2%80%8CBinary%20Tree/README_EN.md) |
| 4 | + |
| 5 | +## 题目描述 |
| 6 | + |
| 7 | +<!-- 这里写题目描述 --> |
| 8 | + |
| 9 | +<p>Given a <strong>0-indexed</strong> integer <strong>2D array</strong> <code>nodes</code>, your task is to determine if the given array represents the <strong>preorder</strong> traversal of some <strong>binary</strong> tree.</p> |
| 10 | + |
| 11 | +<p>For each index <code>i</code>, <code>nodes[i] = [id, parentId]</code>, where <code>id</code> is the id of the node at the index <code>i</code> and <code>parentId</code> is the id of its parent in the tree (if the node has no parent, then <code>parentId = -1</code>).</p> |
| 12 | + |
| 13 | +<p>Return <code>true</code> <em>if the given array </em><em>represents the preorder traversal of some tree, and</em> <code>false</code> <em>otherwise.</em></p> |
| 14 | + |
| 15 | +<p><strong>Note:</strong> the <strong>preorder</strong> traversal of a tree is a recursive way to traverse a tree in which we first visit the current node, then we do the preorder traversal for the left child, and finally, we do it for the right child.</p> |
| 16 | + |
| 17 | +<p> </p> |
| 18 | +<p><strong class="example">Example 1:</strong></p> |
| 19 | + |
| 20 | +<pre> |
| 21 | +<strong>Input:</strong> nodes = [[0,-1],[1,0],[2,0],[3,2],[4,2]] |
| 22 | +<strong>Output:</strong> true |
| 23 | +<strong>Explanation:</strong> The given nodes make the tree in the picture below. |
| 24 | +We can show that this is the preorder traversal of the tree, first we visit node 0, then we do the preorder traversal of the right child which is [1], then we do the preorder traversal of the left child which is [2,3,4]. |
| 25 | +</pre> |
| 26 | + |
| 27 | +<p><img alt="" src="https://fastly.jsdelivr.net/gh/doocs/leetcode@main/solution/2700-2799/2764.is%20Array%20a%20Preorder%20of%20Some%20%E2%80%8CBinary%20Tree/images/1.png" style="padding: 10px; background: #fff; border-radius: .5rem; width: 250px; height: 251px;" /></p> |
| 28 | + |
| 29 | +<p><strong class="example">Example 2:</strong></p> |
| 30 | + |
| 31 | +<pre> |
| 32 | +<strong>Input:</strong> nodes = [[0,-1],[1,0],[2,0],[3,1],[4,1]] |
| 33 | +<strong>Output:</strong> false |
| 34 | +<strong>Explanation:</strong> The given nodes make the tree in the picture below. |
| 35 | +For the preorder traversal, first we visit node 0, then we do the preorder traversal of the right child which is [1,3,4], but we can see that in the given order, 2 comes between 1 and 3, so, it's not the preorder traversal of the tree. |
| 36 | +</pre> |
| 37 | + |
| 38 | +<p><img alt="" src="https://fastly.jsdelivr.net/gh/doocs/leetcode@main/solution/2700-2799/2764.is%20Array%20a%20Preorder%20of%20Some%20%E2%80%8CBinary%20Tree/images/2.png" style="padding: 10px; background: #fff; border-radius: .5rem; width: 250px; height: 251px;" /></p> |
| 39 | + |
| 40 | +<p> </p> |
| 41 | +<p><strong>Constraints:</strong></p> |
| 42 | + |
| 43 | +<ul> |
| 44 | + <li><code>1 <= nodes.length <= 10<sup>5</sup></code></li> |
| 45 | + <li><code>nodes[i].length == 2</code></li> |
| 46 | + <li><code>0 <= nodes[i][0] <= 10<sup>5</sup></code></li> |
| 47 | + <li><code>-1 <= nodes[i][1] <= 10<sup>5</sup></code></li> |
| 48 | + <li>The input is generated such that <code>nodes</code> make a binary tree.</li> |
| 49 | +</ul> |
| 50 | + |
| 51 | +## 解法 |
| 52 | + |
| 53 | +<!-- 这里可写通用的实现逻辑 --> |
| 54 | + |
| 55 | +**方法一:DFS** |
| 56 | + |
| 57 | +我们先根据 $nodes$ 数据构建图 $g$,其中 $g[i]$ 表示节点 $i$ 的所有子节点。 |
| 58 | + |
| 59 | +接下来,设计一个函数 $dfs(i)$,表示从节点 $i$ 开始进行先序遍历,用一个变量 $k$ 表示当前遍历到 $nodes$ 列表的第 $k$ 个节点,初始时 $k=0$。 |
| 60 | + |
| 61 | +函数 $dfs(i)$ 的执行逻辑如下: |
| 62 | + |
| 63 | +- 如果 $i \neq nodes[k][0]$,说明当前序列不是二叉树的先序遍历序列,返回 `false`。 |
| 64 | +- 否则,我们将 $k$ 加 $1$,然后递归搜索 $i$ 的所有子节点,如果搜索过程中发现 `false`,那么提前返回 `false`,否则搜索结束,返回 `true`。 |
| 65 | + |
| 66 | +在主函数中,我们调用 $dfs(nodes[0][0])$,如果返回值为 `true`,并且 $k = |nodes|$,那么 $nodes$ 序列是二叉树的先序遍历序列,返回 `true`,否则返回 `false`。 |
| 67 | + |
| 68 | +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是 $nodes$ 中的节点数目。 |
| 69 | + |
| 70 | +<!-- tabs:start --> |
| 71 | + |
| 72 | +### **Python3** |
| 73 | + |
| 74 | +<!-- 这里可写当前语言的特殊实现逻辑 --> |
| 75 | + |
| 76 | +```python |
| 77 | +class Solution: |
| 78 | + def isPreorder(self, nodes: List[List[int]]) -> bool: |
| 79 | + def dfs(i: int) -> int: |
| 80 | + nonlocal k |
| 81 | + if i != nodes[k][0]: |
| 82 | + return False |
| 83 | + k += 1 |
| 84 | + return all(dfs(j) for j in g[i]) |
| 85 | + |
| 86 | + g = defaultdict(list) |
| 87 | + for i, p in nodes: |
| 88 | + g[p].append(i) |
| 89 | + k = 0 |
| 90 | + return dfs(nodes[0][0]) and k == len(nodes) |
| 91 | +``` |
| 92 | + |
| 93 | +### **Java** |
| 94 | + |
| 95 | +<!-- 这里可写当前语言的特殊实现逻辑 --> |
| 96 | + |
| 97 | +```java |
| 98 | +class Solution { |
| 99 | + private Map<Integer, List<Integer>> g = new HashMap<>(); |
| 100 | + private List<List<Integer>> nodes; |
| 101 | + private int k; |
| 102 | + |
| 103 | + public boolean isPreorder(List<List<Integer>> nodes) { |
| 104 | + this.nodes = nodes; |
| 105 | + for (var node : nodes) { |
| 106 | + g.computeIfAbsent(node.get(1), key -> new ArrayList<>()).add(node.get(0)); |
| 107 | + } |
| 108 | + return dfs(nodes.get(0).get(0)) && k == nodes.size(); |
| 109 | + } |
| 110 | + |
| 111 | + private boolean dfs(int i) { |
| 112 | + if (i != nodes.get(k).get(0)) { |
| 113 | + return false; |
| 114 | + } |
| 115 | + ++k; |
| 116 | + for (int j : g.getOrDefault(i, List.of())) { |
| 117 | + if (!dfs(j)) { |
| 118 | + return false; |
| 119 | + } |
| 120 | + } |
| 121 | + return true; |
| 122 | + } |
| 123 | +} |
| 124 | +``` |
| 125 | + |
| 126 | +### **C++** |
| 127 | + |
| 128 | +```cpp |
| 129 | +class Solution { |
| 130 | +public: |
| 131 | + bool isPreorder(vector<vector<int>>& nodes) { |
| 132 | + int k = 0; |
| 133 | + unordered_map<int, vector<int>> g; |
| 134 | + for (auto& node : nodes) { |
| 135 | + g[node[1]].push_back(node[0]); |
| 136 | + } |
| 137 | + function<bool(int)> dfs = [&](int i) { |
| 138 | + if (i != nodes[k][0]) { |
| 139 | + return false; |
| 140 | + } |
| 141 | + ++k; |
| 142 | + for (int j : g[i]) { |
| 143 | + if (!dfs(j)) { |
| 144 | + return false; |
| 145 | + } |
| 146 | + } |
| 147 | + return true; |
| 148 | + }; |
| 149 | + return dfs(nodes[0][0]) && k == nodes.size(); |
| 150 | + } |
| 151 | +}; |
| 152 | +``` |
| 153 | +
|
| 154 | +### **Go** |
| 155 | +
|
| 156 | +```go |
| 157 | +func isPreorder(nodes [][]int) bool { |
| 158 | + k := 0 |
| 159 | + g := map[int][]int{} |
| 160 | + for _, node := range nodes { |
| 161 | + g[node[1]] = append(g[node[1]], node[0]) |
| 162 | + } |
| 163 | + var dfs func(int) bool |
| 164 | + dfs = func(i int) bool { |
| 165 | + if i != nodes[k][0] { |
| 166 | + return false |
| 167 | + } |
| 168 | + k++ |
| 169 | + for _, j := range g[i] { |
| 170 | + if !dfs(j) { |
| 171 | + return false |
| 172 | + } |
| 173 | + } |
| 174 | + return true |
| 175 | + } |
| 176 | + return dfs(nodes[0][0]) && k == len(nodes) |
| 177 | +} |
| 178 | +``` |
| 179 | + |
| 180 | +### **TypeScript** |
| 181 | + |
| 182 | +```ts |
| 183 | +function isPreorder(nodes: number[][]): boolean { |
| 184 | + let k = 0; |
| 185 | + const g: Map<number, number[]> = new Map(); |
| 186 | + for (const [i, p] of nodes) { |
| 187 | + if (!g.has(p)) { |
| 188 | + g.set(p, []); |
| 189 | + } |
| 190 | + g.get(p)!.push(i); |
| 191 | + } |
| 192 | + const dfs = (i: number): boolean => { |
| 193 | + if (i !== nodes[k][0]) { |
| 194 | + return false; |
| 195 | + } |
| 196 | + ++k; |
| 197 | + for (const j of g.get(i) ?? []) { |
| 198 | + if (!dfs(j)) { |
| 199 | + return false; |
| 200 | + } |
| 201 | + } |
| 202 | + return true; |
| 203 | + }; |
| 204 | + return dfs(nodes[0][0]) && k === nodes.length; |
| 205 | +} |
| 206 | +``` |
| 207 | + |
| 208 | +### **...** |
| 209 | + |
| 210 | +``` |
| 211 | +
|
| 212 | +``` |
| 213 | + |
| 214 | +<!-- tabs:end --> |
0 commit comments