“Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。”
一、题目描述:
统计最高分的节点数目
给你一棵根节点为 0 的 二叉树 ,它总共有 n 个节点,节点编号为 0 到 n - 1 。同时给你一个下标从 0 开始的整数数组 parents 表示这棵树,其中 parents[i] 是节点 i 的父节点。由于节点 0 是根,所以 parents[0] == -1 。
一个子树的 大小 为这个子树内节点的数目。每个节点都有一个与之关联的 分数 。求出某个节点分数的方法是,将这个节点和与它相连的边全部 删除 ,剩余部分是若干个 非空 子树,这个节点的 分数 为所有这些子树 大小的乘积 。
请你返回有 最高得分 节点的 数目 。
二、思路分析:
当删除一个二叉树节点所有边时,如果都存在一般有三部分 该节点的左节点为根节点子树部分, 该节点的右节点为根节点子树部分,以及原来的根节点删去该节点为根节点的子树部分。当然如果不是二叉树,是树,也是n个该节点的节点为根节点的子树,以及原来的根节点删去该节点为根节点的子树部分
故一个节点的得分为 三者的节点数的乘积,为此我们要统计每个节点为根节点的子树的节点数size。这样的话,原来的根节点删去该节点为根节点的子树部分的结点数为 总节点数n-size。现在的问题是如何求得每个节点为根节点的子树的节点数,同时不超时
如果我们用迭代,遍历一个节点,在该节点的所有包含它的祖先节点的节点数量+1,我们为了得到这些祖先节点,还要继续迭代,同时还需要一个哈希表存储节点和其对应子树节点数量,每次读取也需要时间,而且如果该节点也有子节点,那么这个重复过程有增加了。为此会出现超时的情况
我们希望从下而上,即最底下的子节点数量肯定是1,从最底下的节点推出其祖先节点的节点数量,这样就不需要多次重复遍历。而题目给的是二叉树,我们想到二叉树的深度遍历,使用递归的方式就不必多次重复遍历。
因为题目给的是一个number[]数组,为了实现二叉树的深度遍历我们得知道一个节点的孩子结点,才能开始迭代。为此我们创建一个number[][]二维数组,存储对应的子节点。
这个递归函数dfs,返回当前结点为根节点的子树的节点数。同时我们可以在递归的过程中,得出最大的得分和最高得分的节点数目,因为是从下往上的,当前递归的节点已经知道子节点为根节点的子树的节点数,可以轻易的得出。
三、AC代码
/**
- @param {number[]} parents
- @return {number} / var countHighestScoreNodes = function(parents) { if(parents.length<=1)return 0 let node=new Array(parents.length).fill(0).map(i=>new Array()) for(let i=0;i<parents.length;i++){ if(parents[i]!==-1)node[parents[i]].push(i) } let n=parents.length let max=0,count=0 const dfs=function(index){ let size=1 let mul=1 //子节点的节点数 for(let i of node[index]){ let child=dfs(i) size+=child mul=child } if(size!==n){ mul*=(n-size) } if(mul==max)count++ else if(mul>max){ max=mul count=1 } return size } dfs(0) return count };