From 8b65a0e091a6d03aa6f96550a9a8fa098928d93c Mon Sep 17 00:00:00 2001 From: AC_Oier Date: Sat, 12 Mar 2022 15:03:38 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8update:=20Modify=202049?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...10\344\270\255\347\255\211\357\274\211.md" | 59 ++++++++++++++++++- ...10\347\256\200\345\215\225\357\274\211.md" | 2 +- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git "a/LeetCode/2041-2050/2049. \347\273\237\350\256\241\346\234\200\351\253\230\345\210\206\347\232\204\350\212\202\347\202\271\346\225\260\347\233\256\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/2041-2050/2049. \347\273\237\350\256\241\346\234\200\351\253\230\345\210\206\347\232\204\350\212\202\347\202\271\346\225\260\347\233\256\357\274\210\344\270\255\347\255\211\357\274\211.md" index aee8cb5d..dd738841 100644 --- "a/LeetCode/2041-2050/2049. \347\273\237\350\256\241\346\234\200\351\253\230\345\210\206\347\232\204\350\212\202\347\202\271\346\225\260\347\233\256\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/2041-2050/2049. \347\273\237\350\256\241\346\234\200\351\253\230\345\210\206\347\232\204\350\212\202\347\202\271\346\225\260\347\233\256\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -53,12 +53,14 @@ Tag : 「图论」、「线性 DP」 --- -### 建图 + DFS +### 建图 + DFS + 统计答案 为了更具有一般性,我们假定该树为多叉树。 由于题目给定的 `parents` 数组仅支持我们快速查找某个节点的父节点,为了方便遍历整棵树,我们先使用「邻接表」将图(树)建起来。 +还不熟悉「邻接表」存图方式的同学可以看看前置 🧀 : [涵盖所有的「存图方式」模板](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)。 + 然后使用 `DFS` 预处理出 `f` 数组,其中 $f[i]$ 代表以节点 $i$ 为根节点的子树所包含的节点数量。 考虑如何计算「删除某个节点 $x$ 后,剩余连通块的数量,以及每个连通块的节点数量」,根据节点 $x$ 是否为根节点进行分情况讨论: @@ -119,6 +121,61 @@ class Solution { --- +### 拓扑排序 + 统计答案 + +通过对「待删除节点是否为根节点」的分情况讨论可知:若要算得删除某个节点后的得分,重点需要知道「当前节点的左右子树(如果有)所包含的节点数量」以及「当前节点的父节点所在连通块的节点数量」。 + +我们解法 $1$ 的建图目的就是为了得到某个节点的子树情况,`DFS` 预处理 `f` 数组的目的就是知道以某个节点为根的子树所包含的总节点数量。 + +而这个「建图 + `DFS`」过程可由「拓扑排序」所代替。 + +具体的,我们可以先对 `parents`进行遍历, 统计所有节点的出度 $out[i]$,然后将所有出度为 $0$ 的节点(叶子节点)进行入队。跑一遍求拓扑排序的 `BFS`,每次某个节点 $t$ 出队,我们就对节点 $t$ 的父节点 $fa = parents[t]$ 进行出度减一操作(若出度减至 $0$,则将 $fa$ 进行入队,注意 $fa$ 不能为根节点,因为 $fa$ 入队没有意义,其入队不能更新其他点的出度),并在求拓扑序的过程中预处理出 `l` 和 `r` 数组,$l[i]$ 和 $r[i]$ 分别代表节点 $i$ 的左子树的节点数和右节点的节点数。 + +跑完拓扑排序后,我们得到的 `l` 和 `r` 数组就足够我们统计答案,仍然是对删除节点 $x$ 是否为根节点的分情况讨论: + +* 若 $x$ 不是根节点,得分为 $\max(l[x], 1) \times \max( r[x], 1)$ +* 若 $x$ 为根节点,得分为 $\max(l[x], 1) \times \max( r[x], 1) \times (n - (l[x] + r[x] + 1)$ + +代码: +```Java +class Solution { + public int countHighestScoreNodes(int[] parents) { + int n = parents.length; + int[] out = new int[n]; + for (int i = 1; i < n; i++) out[parents[i]]++; + Deque d = new ArrayDeque<>(); + for (int i = 0; i < n; i++) { + if (out[i] == 0) d.addLast(i); + } + // l[i] 和 r[i] 分别代表节点 i 的左子树的节点数和右节点的节点数 + int[] l = new int[n], r = new int[n]; + while (!d.isEmpty()) { + int t = d.pollFirst(), fa = parents[t]; + out[fa]--; + if (l[fa] == 0) l[fa] = l[t] + r[t] + 1; + else r[fa] = l[t] + r[t] + 1; + if (out[fa] == 0 && fa != 0) d.addLast(fa); + } + long max = 0; + int ans = 0; + for (int i = 0; i < n; i++) { + long cur = Math.max(l[i], 1) * Math.max(r[i], 1); + if (i != 0) cur *= n - (l[i] + r[i] + 1); + if (cur > max) { + max = cur; ans = 1; + } else if (cur == max) { + ans++; + } + } + return ans; + } +} +``` +* 时间复杂度:$O(n)$ +* 空间复杂度:$O(n)$ + +--- + ### 最后 这是我们「刷穿 LeetCode」系列文章的第 `No.2049` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 diff --git "a/LeetCode/581-590/590. N \345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\357\274\210\347\256\200\345\215\225\357\274\211.md" "b/LeetCode/581-590/590. N \345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\357\274\210\347\256\200\345\215\225\357\274\211.md" index 4fe43be7..33f6671f 100644 --- "a/LeetCode/581-590/590. N \345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\357\274\210\347\256\200\345\215\225\357\274\211.md" +++ "b/LeetCode/581-590/590. N \345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206\357\274\210\347\256\200\345\215\225\357\274\211.md" @@ -1,6 +1,6 @@ ### 题目描述 -这是 LeetCode 上的 **[590. N 叉树的后序遍历(简单)](https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/solution/by-ac_oier-ul7t/)** ,难度为 **简单**。 +这是 LeetCode 上的 **[590. N 叉树的后序遍历](https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/solution/by-ac_oier-ul7t/)** ,难度为 **简单**。 Tag : 「递归」、「迭代」、「非递归」、「DFS」、「BFS」