给定一个无向、连通的树。树中有 N 个标记为 0…N-1 的节点以及 N-1 条边 。
第 i 条边连接节点 edges[i][0] 和 edges[i][1] 。
返回一个表示节点 i 与其他所有节点距离之和的列表 ans。
输入: N = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]]
输出: [8,12,6,10,10,10]
解释:
如下为给定的树的示意图:
0
/ \
1 2
/|\
3 4 5
我们可以计算出 dist(0,1) + dist(0,2) + dist(0,3) + dist(0,4) + dist(0,5)
也就是 1 + 1 + 2 + 2 + 2 = 8。 因此,answer[0] = 8,以此类推。
说明: 1 <= N <= 10000
dfs
将一棵树拆成两个子树,子树的根节点分别为A、B,显然A、B节点是相邻的。我们可得所有节点到A的距离和ans[A] = A子树中所有节点到A节点的距离和sum[A]+B子树中所有节点到B节点的距离和sum[B]+Bz子树中节点个数cnt[B],我们简写为ans[A] = sum[A] + sum[B] + cnt[B];同理,我们可以得到ans[B] = sum[B] + sum[A] + cnt[A]。
两式作差可以得到ans[A] = cnt[B] - cnt[A] + ans[B],因为cnt[A]+cnt[B] = N的,因此ans[A] = cnt[B] - cnt[A] + ans[B] + cnt[A] - cnt[A] = ans[B] - cnt[A] + (N-cnt[A])。我们不妨把A看作子节点,B看作是父节点。
我们两次dfs,一次获取每个节点作为根节点的子树中节点的个数,即cnt;一次用来获取答案,也就是ans。
详细过程见代码
vector<int> visit;
vector<int> cnt;
int dfs(int now,int height,unordered_map<int,vector<int>>& tree){
int ans = height;
visit[now] = 1;
for(int i=0; i<tree[now].size(); i++){
if(visit[tree[now][i]] == 0){
ans += dfs(tree[now][i],height+1,tree);
cnt[now] += cnt[tree[now][i]];
}
}
cnt[now]++;
return ans;
}
//ans[x] = x@ + y@ + cnty
//ans[y] = y@ + x@ + cntx
//ans[x] = ans[y] + cnty -cntx
void dfs2(int now,int parent,int N,vector<int>&ans,unordered_map<int,vector<int>>& tree){
visit[now] = 1;
if(parent!=-1){
ans[now] = ans[parent] - cnt[now] + (N-cnt[now]);
}
for(int i=0; i<tree[now].size(); i++){
if(visit[tree[now][i]] == 0){
dfs2(tree[now][i],now,N,ans,tree);
}
}
}
vector<int> sumOfDistancesInTree(int N, vector<vector<int>>& edges) {
unordered_map<int,vector<int>> tree;
vector<int> ans(N,0);
visit = vector<int>(N,0);
cnt = vector<int>(N,0);
for(int i=0; i<edges.size(); i++){
tree[edges[i][0]].push_back(edges[i][1]);
tree[edges[i][1]].push_back(edges[i][0]);
}
ans[0] = dfs(0,0,tree); //统一将0作为树的根节点
visit = vector<int>(N,0);
dfs2(0,-1,N,ans,tree);
return ans;
}
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-distances-in-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。