思路:
题目的主要信息:
- 一棵树每边长度为1,节点到节点的距离为
- 某个节点的权值
- 现求树每个节点的权值
方法一:两次dfs
具体做法:
我们可以用两次dfs解决这个问题。
第一次dfs遍历这棵树,找到每个节点有多少个子节点,第二次dfs遍历每个节点,根据第一次找到的子节点数推算出到其他任何节点的距离。
public: vector<int> G[100001]; vector<int> s; //记录每个子树的结点数 vector<long> res; int dfs1(int u, int p, int d){ //u为当前节点,p为递归过来的前一个结点 int cnt = 1; for(int i = 0; i < G[u].size(); i++) if(G[u][i] != p) cnt += dfs1(G[u][i], u, d + 1); res[0] += d; s[u] = cnt; return cnt; } void dfs2(int u, int p, int n){//u为当前节点,p为前一个结点 for(int i = 0; i < G[u].size(); i++){ if(G[u][i] != p){ res[G[u][i]] = res[u] + n - 2 * s[G[u][i]]; dfs2(G[u][i], u, n); } } } vector<long> solve(int n, vector<Point>& edge) { s.resize(n); res.resize(n); for(int i = 0; i < edge.size(); i++){ //构建图 G[edge[i].x - 1].push_back(edge[i].y - 1); G[edge[i].y - 1].push_back(edge[i].x - 1); } dfs1(0, -1, 0); //深度优先每一个节点,计算每个子树有多少节点 dfs2(0, -1, n); //根据每个子树节点数,计算到每个节点的距离和 return res; } };
复杂度分析:
- 时间复杂度:,两次dfs递归,各自遍历每一个节点
- 空间复杂度:,递归栈最大深度及辅助数组s,其中res属于返回必要空间
方法二:bfs
具体做法:
因为树的bfs是层次遍历,对于每一层,祖先节点到其的距离都是相同的,利用这个性质,我们可以对于每一个节点进行遍历,然后以该节点作为bfs的起点开始计算总的距离。到达每一层的时,队列中的元素个数就是这一层的节点数,只需要加上该层的层号即是距离。
class Solution { public: int bfs(vector<vector<int>>& g, int n, int start) { deque<int> q{{start}}; vector<bool> vis(n + 1, false); vis[start] = true; long res = 0; int layers = 0; //层数 while(!q.empty()) { int s = q.size(); //当前层节点数 while(s--){ //一层内距离相同 int cur = q.front(); q.pop_front(); res += layers; for(int i = 0; i < g[cur].size(); i++){ if(vis[g[cur][i]]) //没有访问过的 continue; vis[g[cur][i]] = true; q.push_back(g[cur][i]); } } layers++; //层数增加 } return res; } vector<long> solve(int n, vector<Point>& edge) { vector<long> res(n); vector<vector<int> > G(n + 1); for(int i = 0; i < edge.size(); i++){ //构建图 G[edge[i].x].push_back(edge[i].y); G[edge[i].y].push_back(edge[i].x); } for (int i = 1; i <= n; i++)//遍历每个节点,bfs求距离 res[i - 1] = bfs(G, n, i); return res; } };
复杂度分析:
- 时间复杂度:,对于每个节点,都有一次bfs,每次复杂度为
- 空间复杂度:,辅助数组G最坏情况为邻接矩阵