思路(自己):除了根节点无父节点外,去除其余节点必定会与父节点分离。每次切割之后都要考虑消除了几个分支。若消除的是k节点,查询数组,(for i=0;i<a.length;i++)a[i]==k的情况必有0~2个。
(需注意:以下情况为k不为0,即k不是根节点的情况下,是根节点则比较特殊,在实现过程中出过错!!!)
- 若为0个,则该节点为叶子节点,分数为a.length-1;
- 若为1个,则切割完之后有两部分。(怎么确定两部分的数目呢?)
- 若为2个,则切割完之后有三部分。
确定以节点K为根节点的子树所含元素大小,通过一个函数实现:int treeSum;使用迭代的思想。
//定义treeSum函数,返回以指定节点为根节点的子树元素个数
int treeSum(int num, ArrayList<Integer> list){
int n=1;
//如果该节点没有子节点,说明是叶子节点,返回1
if(!list.contains(num))
return n;
//该节点只有一个子节点,返回子节点数目+1
if(list.indexOf(num)==list.lastIndexOf(num))
return treeSum(list.indexOf(num),list)+1;
return treeSum(list.indexOf(num),list)+treeSum(list.lastIndexOf(num),list)+1;
}
然后通过for循坏,把每次的得分情况存入list1中,最后进行排序,去最后一个元素,记录最后一个元素的个数,即为解。实现过程如下:
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
class Solution {
public int countHighestScoreNodes(int[] parents) {
//将数组元素导入list中方便操作
ArrayList<Integer> list= new ArrayList<>(parents.length);
for(Integer i:parents){
list.add(i);
}
//定义list1存储去除每个元素后的得分
List<Integer> list1=new ArrayList<>(parents.length);
//根节点需要特殊对待
if(!list.contains(0)){
list1.add(0);
}else if(list.indexOf(0)==list.lastIndexOf(0)){
list1.add(parents.length-1);
}else {
int son=list.indexOf(0);
int j=treeSum(son,list);
// int k=treeSum(0,list)-j-1;
list1.add(j*(parents.length-j-1));
}
for (int i = 1; i < parents.length; i++) {
//如果节点不含子节点,则其为叶子节点,分数为总长度减一
if(!list.contains(i)){
list1.add(parents.length-1);
continue;
}
//如果只有一个子树,则分割后为两部分
if(list.indexOf(i)==list.lastIndexOf(i)){
int j=treeSum(i,list);
list1.add((j-1)*(parents.length-j));
continue;
}
//含有两个子树,分割后为三部分
if(list.indexOf(i)!=list.lastIndexOf(i)){
int son=list.indexOf(i);
int j=treeSum(son,list);
int k=treeSum(i,list)-j-1;
list1.add(j*k*(parents.length-1-j-k));
continue;
}
}
Collections.sort(list1);
int max=list1.get(list1.size()-1);
int res=0;
for(Integer i:list1){
if(i==max) res++;
}
return res;
}
//定义treeSum函数,返回以指定节点为根节点的子树元素个数
int treeSum(int num, ArrayList<Integer> list){
int n=1;
//如果该节点没有子节点,说明是叶子节点,返回1
if(!list.contains(num))
return n;
//该节点只有一个子节点,返回子节点数目+1
if(list.indexOf(num)==list.lastIndexOf(num))
return treeSum(list.indexOf(num),list)+1;
return treeSum(list.indexOf(num),list)+treeSum(list.lastIndexOf(num),list)+1;
}
}
这个题我做了接近两个小时,算是比较悲伤的了,┭┮﹏┭┮ 最后让人绝望的是又超出时间限制了!
好了,看完官方答案,看不懂,看了另一位大牛的,勉强理解了
class Solution {
//使用两个数组保存二叉树的左右节点,索引为父节点
int[] left, right;
//最大分数, 注意溢出,这里用 long
long maxScore;
//最大分数量
int cnt;
//整棵树大小
int n;
public int countHighestScoreNodes(int[] parents) {
n = parents.length;
left = new int[n];
right = new int[n];
//初始化树的表示,-1表示空节点
Arrays.fill(left, -1);
Arrays.fill(right, -1);
//构建树的表示
for (int i = 1; i < n; i++) {
//填充左右节点无所谓,这里优先填左节点
if (left[parents[i]] == -1) {
left[parents[i]] = i;
} else {
right[parents[i]] = i;
}
}
//dfs处理更新相关值
dfs(0);
return cnt;
}
//返回以此节点为根节点的子树的大小
private long dfs(int node) {
if (node == -1) {
return 0;
}
//dfs 获取左右子树大小
long leftSize = dfs(left[node]), rightSize = dfs(right[node]);
//计算三个联通块的乘积
long score = Math.max(leftSize, 1) * Math.max(rightSize, 1) * Math.max(n - leftSize - rightSize - 1, 1);
if (score == maxScore) {
cnt++;
} else if (score > maxScore) {
maxScore = score;
cnt = 1;
}
return leftSize + rightSize + 1;
}
}
实力还有待提高!