Redian新闻
>
LeetCode 力扣官方题解 | 2049. 统计最高分的节点数目

LeetCode 力扣官方题解 | 2049. 统计最高分的节点数目

公众号新闻

2049. 统计最高分的节点数目

题目描述

难易度:中等

给你一棵根节点为 0 的 二叉树 ,它总共有 n 个节点 ,节点编号为 0 到 n - 1 。同时给你一个下标从 0 开始的整数数组 parents 表示这棵树 ,其中 parents[i] 是节点 i 的父节点 。由于节点 0 是根 ,所以 parents [0] == -1 。

一个子树的 大小 为这个子树内节点的数目 。每个节点都有一个与之关联的 分数 。求出某个节点分数的方法是 ,将这个节点和与它相连的边全部 删除 ,剩余部分是若干个 非空 子树 ,这个节点的 分数 为所有这些子树 大小的乘积

请你返回有 最高得分 节点的 数目

示例 1:

 

输入:parents = [-1,2,0,2,0]输出:3解释:- 节点 0 的分数为:3 * 1 = 3- 节点 1 的分数为:4 = 4- 节点 2 的分数为:1 * 1 * 2 = 2- 节点 3 的分数为:4 = 4- 节点 4 的分数为:4 = 4最高得分为 4 ,有三个节点得分为 4 (分别是节点 1,3 和 4 )


示例 2:

输入:parents = [-1,2,0]输出:2解释:- 节点 0 的分数为:2 = 2- 节点 1 的分数为:2 = 2- 节点 2 的分数为:1 * 1 = 1最高分数为 2 ,有两个节点分数为 2 (分别为节点 0 和 1 )。


提示:

  • n == parents.length

  • 2 <= n <= 105

  • parents[0] == -1

  • 对于 i != 0 ,有 0 <= parents[i] <= n - 1

  • parents 表示一棵二叉树。


解决方案

方法一:深度优先搜素

思路

在一棵树中,当把一个节点和与它相连的所有边删除,剩余部分最多为三棵非空子树,即原节点的左子树(如果有),右子树(如果有),以及把以这个节点为根结点的子树移除所形成的子(除根结点外均有)。而这个节点的分数为这些子树的节点个数的乘积。我们可以先用 parents 数组统计出每个节点的子节点,然后使用深度优先搜索来计算以每个节点为根结点的子树的大小,同时计算每个节点的大小,作为深度优先搜索的返回值,最后统计最大分数出现的次数。在实现上,统计最大分数出现的次数可以放到深度优先搜索中完成,从而节省一部分空间。

代码

Python3

class Solution:    def countHighestScoreNodes(self, parents: List[int]) -> int:        n = len(parents)        children = [[] for _ in range(n)]        for node, p in enumerate(parents):            if p != -1:                children[p].append(node)

maxScore, cnt = 0, 0 def dfs(node: int) -> int: score = 1 size = n - 1 for ch in children[node]: sz = dfs(ch) score *= sz size -= sz if node != 0: score *= size nonlocal maxScore, cnt if score == maxScore: cnt += 1 elif score > maxScore: maxScore, cnt = score, 1 return n - size dfs(0)        return cnt


Java

class Solution {    long maxScore = 0;    int cnt = 0;    int n;    List<Integer>[] children;

public int countHighestScoreNodes(int[] parents) { n = parents.length; children = new List[n]; for (int i = 0; i < n; i++) { children[i] = new ArrayList<Integer>(); } for (int i = 0; i < n; i++) { int p = parents[i]; if (p != -1) { children[p].add(i); } } dfs(0); return cnt; }

public int dfs(int node) { long score = 1; int size = n - 1; for (int c : children[node]) { int t = dfs(c); score *= t; size -= t; } if (node != 0) { score *= size; } if (score == maxScore) { cnt++; } else if (score > maxScore) { maxScore = score; cnt = 1; } return n - size; }}

C#

public class Solution {    long maxScore = 0;    int cnt = 0;    int n;    IList<int>[] children;

public int CountHighestScoreNodes(int[] parents) { n = parents.Length; children = new IList<int>[n]; for (int i = 0; i < n; i++) { children[i] = new List<int>(); } for (int i = 0; i < n; i++) { int p = parents[i]; if (p != -1) { children[p].Add(i); } } DFS(0); return cnt; }

public int DFS(int node) { long score = 1; int size = n - 1; foreach (int c in children[node]) { int t = DFS(c); score *= t; size -= t; } if (node != 0) { score *= size; } if (score == maxScore) { cnt++; } else if (score > maxScore) { maxScore = score; cnt = 1; } return n - size; }}


C++

class Solution {public:    long maxScore = 0;    int cnt = 0;    int n;    vector<vector<int>> children;

int dfs(int node) { long score = 1; int size = n - 1; for (int c : children[node]) { int t = dfs(c); score *= t; size -= t; } if (node != 0) { score *= size; } if (score == maxScore) { cnt++; } else if (score > maxScore) { maxScore = score; cnt = 1; } return n - size; }

int countHighestScoreNodes(vector<int>& parents) { this->n = parents.size(); this->children = vector<vector<int>>(n); for (int i = 0; i < n; i++) { int p = parents[i]; if (p != -1) { children[p].emplace_back(i); } } dfs(0); return cnt; }};


C

int dfs(int node, long * maxScore, int * cnt, int n, const struct ListNode ** children) {    long score = 1;    int size = n - 1;    for (struct ListNode * curr = children[node]; curr; curr = curr->next) {        int t = dfs(curr->val, maxScore, cnt, n, children);        score *= t;        size -= t;    }    if (node != 0) {        score *= size;    }    if (score == *maxScore) {        (*cnt)++;    } else if (score > *maxScore) {        *maxScore = score;        *cnt = 1;    }    return n - size;}

int countHighestScoreNodes(int* parents, int parentsSize){ int n = parentsSize; int cnt = 0; long maxScore = 0; struct ListNode ** children = (struct ListNode **)malloc(sizeof(struct ListNode *) * n); for (int i = 0; i < n; i++) { children[i] = NULL; } for (int i = 0; i < n; i++) { int p = parents[i]; if (p != -1) { struct ListNode * node = (struct ListNode *)malloc(sizeof(struct ListNode)); node->val = i; node->next = children[p]; children[p] = node; } } dfs(0, &maxScore, &cnt, n, children); for (int i = 0; i < n; i++) { for (struct ListNode * curr = children[i]; curr; ) { struct ListNode * next = curr->next; free(curr); curr = next; } } free(children); return cnt;}


Golang



func countHighestScoreNodes(parents []int) (ans int) { n := len(parents) children := make([][]int, n) for node := 1; node < n; node++ { p := parents[node] children[p] = append(children[p], node) }

maxScore := 0 var dfs func(int) int dfs = func(node int) int { score, size := 1, n-1 for _, ch := range children[node] { sz := dfs(ch) score *= sz size -= sz } if node > 0 { score *= size } if score == maxScore { ans++ } else if score > maxScore { maxScore = score ans = 1 } return n - size } dfs(0) return}


JavaScript

var countHighestScoreNodes = function(parents) {    const n = parents.length;    const children = new Array(n).fill(0);    let maxScore = 0;    let cnt = 0;    for (let i = 0; i < n; i++) {        children[i] = [];    }    for (let i = 0; i < n; i++) {        const p = parents[i];        if (p !== -1) {            children[p].push(i);        }    }

const dfs = (node) => { let score = 1; let size = n - 1; for (const c of children[node]) { let t = dfs(c); score *= t; size -= t; } if (node !== 0) { score *= size; } if (score === maxScore) { cnt++; } else if (score > maxScore) { maxScore = score; cnt = 1; } return n - size; }

dfs(0); return cnt;};


复杂度分析

  • 时间复杂度:O(n),其中 nn 是树的节点数。预处理,深度优先搜索均消耗 O(n) 时间。

  • 空间复杂度:O(n)。统计每个节点的子节点消耗 O(n) 空间,深度优先搜索的深度最多为 O(n) 空间。


BY / 

本文作者:力扣

编辑&版式:Vikki

声明:本文归“力扣”版权所有,如需转载请联系。

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
IEEE标准协会网络研讨会 | PRODUCT SHOWCASE: IEEE EQ NAVIGATOR0基础留学生转码必备:LeetCode到底该怎么速通?打卡LeetCode的第100天,我才发现......背完LeetCode刷题模板,真的不一样!(已拿字节offer)注意!眼下比有刷LeetCode更重要的事…为什么美国在全球找敌人?中国在全球找朋友?退休 23-媛媛病了德国“帝国公民”是什么公民?礼向上,法向下深度好文|打卡LeetCode的第100天,我才发现......刷完 LeetCode 是什么水平?能拿到什么等级的Offer?LeetCode 力扣官方题解 | 590. N 叉树的后序遍历首次免费送!Leetcode刷题速通指南,转码留学生请低调使用!并发提升20+倍、单节点数万QPS,Apache Doris高并发特性解读Layoff潮,对传统刷LeetCode发起新挑战!深度好文|刷完 LeetCode 是什么水平?能拿到什么等级的Offer?靠LeetCode刷题模板,学妹“开奖”字节offer!LeetCode 力扣官方题解 | 521. 最长特殊序列 ⅠNeurIPS 2022 | 大图上线性复杂度的节点级Transformer2023开年16天上岸谷歌,Leetcode刷题小抄背完,面试真的不一样…LeetCode 力扣官方题解 | 953. 验证外星语词典谷歌亚麻,越来越嫌弃Leetcode刷题家…LeetCode 力扣官方题解 | 258. 各位相加LeetCode 力扣官方题解 | 2055. 蜡烛之间的盘子并发提升 20+ 倍、单节点数万 QPS,Apache Doris 高并发特性解读LeetCode 力扣官方题解 | 806. 写字符串需要的行数LeetCode 力扣官方题解 | 6. Z 字形变换冲!阿凡达明天上映!告诉你两个最佳上厕所的节点!中国抗击疫情到了重要转折关头LeetCode 力扣官方题解 | 2104. 子数组范围和拿下6家offer经验分享:刷LeetCode这件事,其实不靠努力!注意!眼下比刷LeetCode更重要的事老鸟也难逃一劫,Leetcode刷题家今年是真的惨!NeurIPS22丨大图上线性复杂度的节点级 Transformer留学圈疯传!商科生转码《Leetcode刷题指南》,信息量太大
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。