2049. 统计最高分的节点数目题解
题目来源:2049. 统计最高分的节点数目
2022.03.11 每日一题
LeetCode 题解持续更新中Github仓库地址 CSDN博客地址
今天的题目眨眼一看可能有点懵逼没太看明白,第一反应是相乘的最大值,那不就是把0
扔出去就行了,思路这么简单的话,middle不太可能,一仔细看,发现与节点对应的 value 值无关,是除了删除节点以外构成树的大小的乘积
那让我们来理性分析一下(以通用情况分析,并非单单只有 二叉树)
一棵树,删除了一个节点以后他还剩什么
让我们来讨论一下,
- 如果删除的点是根节点,那么剩下的东西就是根节点的各个子节点形成的新的树,那么其结果就应该是 s u m = f ( u 1 ) + f ( u 2 ) + f ( u 3 ) + … … + f ( u k ) sum=f(u_1)+f(u_2)+f(u_3)+……+f(u_k) sum=f(u1)+f(u2)+f(u3)+……+f(uk)
- 如果删除的是非根节点,那么最后剩余的东西就是,以删除节点为根节点的各个子节点形成的新的树
+
删除节点其祖先节点其余的树 s u m = f ( u 1 ) + f ( u 2 ) + … … + f ( u k ) + f ( r l ) sum=f(u_1)+f(u_2)+……+f(u_k)+f(r_l) sum=f(u1)+f(u2)+……+f(uk)+f(rl)
一共就这两种情况汇总一下就是 拿到一个节点,最后会剩下一个左子树(如果存在的话)、一个右子树(如果存在的话)、以及一个其祖先节点剩余的部分(如果删除节点不是根节点的话)
现在问题就拆分的很简单了,分别计算三种树的数量最后相乘,左右两个子树计算起来还容易,那么剩下的那个怎么办呢,我们可以使用树的总体大小减去左右子树的大小后 再 减一(减一是减去删除的节点)
class Solution {
public:
// 创建一个 哈希表,key 表示父节点,val 表示子节点集合
unordered_map<int, vector<int>> cnt;
vector<int> f;
int countHighestScoreNodes(vector<int> &parents) {
int len = parents.size();
for (int i = 1; i < len; i++)
cnt[parents[i]].push_back(i);
// 定义数组 f 来存储各个节点的值
f = vector(len, 0);
dfs(0);
// 统计得分最高的树的个数
int res = 0;
// 统计当前得分最高的分数
long long ans = 0;
// 遍历数组 f ,判断
for (int i = 0; i < len; i++) {
// 统计当前情况下的乘积
long temp = 1;
// 遍历 i 的子节点,统计各个树的大小
for (int num: cnt[i])
temp *= f[num];
// 判断当前节点是否是根节点
if (i != 0)
temp *= len - f[i];
// 判断 是否是当前结果最大值
// 如果不是,更新最大值,并且重置 结果 res
if (temp > ans) {
ans = temp;
res = 1;
} else if (ans == temp) {
// 如果与最大值相同,结果加一
res++;
}
}
return res;
}
// 定义递归函数
int dfs(int start) {
// 定义变量统计相应节点的个数
int sum = 1;
// 遍历 节点 start 旗下的子节点,继续向下递归
for (int num: cnt[start]) {
sum += dfs(num);
}
// 将 sum 值进行统计,执行记忆化搜索
f[start] = sum;
// 返回 sum 值供上一层进行使用
return sum;
}
};
class Solution {
// 创建一个 哈希表,key 表示父节点,val 表示子节点集合
Map<Integer, ArrayList<Integer>> cnt = new HashMap();
int[] f;
public int countHighestScoreNodes(int[] parents) {
int len = parents.length;
for (int i = 1; i < len; i++) {
ArrayList<Integer> arr = cnt.getOrDefault(parents[i], new ArrayList<>());
arr.add(i);
cnt.put(parents[i], arr);
}
// 定义数组 f 来存储各个节点的值
f = new int[len];
dfs(0);
// 统计得分最高的树的个数
int res = 0;
// 统计当前得分最高的分数
long ans = 0;
// 遍历数组 f ,判断
for (int i = 0; i < len; i++) {
// 统计当前情况下的乘积
long temp = 1;
// 遍历 i 的子节点,统计各个树的大小
for (int num : cnt.getOrDefault(i, new ArrayList<>()))
temp *= f[num];
// 判断当前节点是否是根节点
if (i != 0) temp *= len - f[i];
// 判断 是否是当前结果最大值
// 如果不是,更新最大值,并且重置 结果 res
if (temp > ans) {
ans = temp;
res = 1;
} else if (ans == temp) {
// 如果与最大值相同,结果加一
res++;
}
}
return res;
}
// 定义递归函数
int dfs(int start) {
// 定义变量统计相应节点的个数
int sum = 1;
// 遍历 节点 start 旗下的子节点,继续向下递归
for (int num : cnt.getOrDefault(start, new ArrayList<>())) {
sum += dfs(num);
}
// 将 sum 值进行统计,执行记忆化搜索
f[start] = sum;
// 返回 sum 值供上一层进行使用
return sum;
}
}