Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7474615

Browse files
Merge pull request SharingSource#406 from SharingSource/ac_oier
✨update: Modify 2049
2 parents 38dfdc1 + 8b65a0e commit 7474615

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

‎LeetCode/2041-2050/2049. 统计最高分的节点数目(中等).md‎

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,14 @@ Tag : 「图论」、「线性 DP」
5353

5454
---
5555

56-
### 建图 + DFS
56+
### 建图 + DFS + 统计答案
5757

5858
为了更具有一般性,我们假定该树为多叉树。
5959

6060
由于题目给定的 `parents` 数组仅支持我们快速查找某个节点的父节点,为了方便遍历整棵树,我们先使用「邻接表」将图(树)建起来。
6161

62+
还不熟悉「邻接表」存图方式的同学可以看看前置 🧀 : [涵盖所有的「存图方式」模板](https%3A//mp.weixin.qq.com/s?__biz%3DMzU4NDE3MTEyMA%3D%3D%26mid%3D2247488007%26idx%3D1%26sn%3D9d0dcfdf475168d26a5a4bd6fcd3505d%26chksm%3Dfd9cb918caeb300e1c8844583db5c5318a89e60d8d552747ff8c2256910d32acd9013c93058f%26mpshare%3D1%26scene%3D23%26srcid%3D0311tjKy74JijYzXhHo8Qob7%26sharer_sharetime%3D1646964421353%26sharer_shareid%3D1221771780968b30ef07c3f22cd356ed%2523rd)
63+
6264
然后使用 `DFS` 预处理出 `f` 数组,其中 $f[i]$ 代表以节点 $i$ 为根节点的子树所包含的节点数量。
6365

6466
考虑如何计算「删除某个节点 $x$ 后,剩余连通块的数量,以及每个连通块的节点数量」,根据节点 $x$ 是否为根节点进行分情况讨论:
@@ -119,6 +121,61 @@ class Solution {
119121

120122
---
121123

124+
### 拓扑排序 + 统计答案
125+
126+
通过对「待删除节点是否为根节点」的分情况讨论可知:若要算得删除某个节点后的得分,重点需要知道「当前节点的左右子树(如果有)所包含的节点数量」以及「当前节点的父节点所在连通块的节点数量」。
127+
128+
我们解法 1ドル$ 的建图目的就是为了得到某个节点的子树情况,`DFS` 预处理 `f` 数组的目的就是知道以某个节点为根的子树所包含的总节点数量。
129+
130+
而这个「建图 + `DFS`」过程可由「拓扑排序」所代替。
131+
132+
具体的,我们可以先对 `parents`进行遍历, 统计所有节点的出度 $out[i],ドル然后将所有出度为 0ドル$ 的节点(叶子节点)进行入队。跑一遍求拓扑排序的 `BFS`,每次某个节点 $t$ 出队,我们就对节点 $t$ 的父节点 $fa = parents[t]$ 进行出度减一操作(若出度减至 0ドル,ドル则将 $fa$ 进行入队,注意 $fa$ 不能为根节点,因为 $fa$ 入队没有意义,其入队不能更新其他点的出度),并在求拓扑序的过程中预处理出 `l``r` 数组,$l[i]$ 和 $r[i]$ 分别代表节点 $i$ 的左子树的节点数和右节点的节点数。
133+
134+
跑完拓扑排序后,我们得到的 `l``r` 数组就足够我们统计答案,仍然是对删除节点 $x$ 是否为根节点的分情况讨论:
135+
136+
* 若 $x$ 不是根节点,得分为 $\max(l[x], 1) \times \max( r[x], 1)$
137+
* 若 $x$ 为根节点,得分为 $\max(l[x], 1) \times \max( r[x], 1) \times (n - (l[x] + r[x] + 1)$
138+
139+
代码:
140+
```Java
141+
class Solution {
142+
public int countHighestScoreNodes(int[] parents) {
143+
int n = parents.length;
144+
int[] out = new int[n];
145+
for (int i = 1; i < n; i++) out[parents[i]]++;
146+
Deque<Integer> d = new ArrayDeque<>();
147+
for (int i = 0; i < n; i++) {
148+
if (out[i] == 0) d.addLast(i);
149+
}
150+
// l[i] 和 r[i] 分别代表节点 i 的左子树的节点数和右节点的节点数
151+
int[] l = new int[n], r = new int[n];
152+
while (!d.isEmpty()) {
153+
int t = d.pollFirst(), fa = parents[t];
154+
out[fa]--;
155+
if (l[fa] == 0) l[fa] = l[t] + r[t] + 1;
156+
else r[fa] = l[t] + r[t] + 1;
157+
if (out[fa] == 0 && fa != 0) d.addLast(fa);
158+
}
159+
long max = 0;
160+
int ans = 0;
161+
for (int i = 0; i < n; i++) {
162+
long cur = Math.max(l[i], 1) * Math.max(r[i], 1);
163+
if (i != 0) cur *= n - (l[i] + r[i] + 1);
164+
if (cur > max) {
165+
max = cur; ans = 1;
166+
} else if (cur == max) {
167+
ans++;
168+
}
169+
}
170+
return ans;
171+
}
172+
}
173+
```
174+
* 时间复杂度:$O(n)$
175+
* 空间复杂度:$O(n)$
176+
177+
---
178+
122179
### 最后
123180

124181
这是我们「刷穿 LeetCode」系列文章的第 `No.2049` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

‎LeetCode/581-590/590. N 叉树的后序遍历(简单).md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
### 题目描述
22

3-
这是 LeetCode 上的 **[590. N 叉树的后序遍历(简单)](https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/solution/by-ac_oier-ul7t/)** ,难度为 **简单**
3+
这是 LeetCode 上的 **[590. N 叉树的后序遍历](https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/solution/by-ac_oier-ul7t/)** ,难度为 **简单**
44

55
Tag : 「递归」、「迭代」、「非递归」、「DFS」、「BFS」
66

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /