【Leetcode算法】Sum of Distances in Tree 树中距离之和

Sum of Distances in Tree 树中距离之和

问题描述:

给定一个无向、连通的树。树中有 n 个标记为 0…n-1 的节点以及 n-1 条边 。

给定整数 n 和数组 edges , e d g e s [ i ] = [ a i , b i ] edges[i] = [a_i, b_i] edges[i]=[ai,bi]表示树中的节点 ai 和 bi 之间有一条边。

返回长度为 n 的数组 answer ,其中 answer[i] 是树中第 i 个节点与所有其他节点之间的距离之和。

1 < = n < = 3 ∗ 1 0 4 e d g e s . l e n g t h = = n − 1 e d g e s [ i ] . l e n g t h = = 2 0 < = a i , b i < n a i ! = b i 给定的输入保证为有效的树 1 <= n <= 3 * 10^4\\ edges.length == n - 1\\ edges[i].length == 2\\ 0 <= a_i, b_i < n\\ a_i != b_i\\ 给定的输入保证为有效的树 1<=n<=3104edges.length==n1edges[i].length==20<=ai,bi<nai!=bi给定的输入保证为有效的树

分析

这是一个以边数组的格式给出的树。要计算出每个节点到其他的节点的距离之和。

对于单个节点,一定是使用dfs,依次计算出每个节点距离root的depth,然后累加,时间复杂度 O ( N ) O(N) O(N)

但是要每一个都跑一遍dfs,很明显是 O ( N 2 ) O(N^2) O(N2).

所以需要其他的方法,来更有效的计算。

策略

如果以a 为root,计算得到的distance为x,下一个计算a的一个子节点b,实际上是不需要重新计算所有的节点距离,只需要知道距离哪些节点近了,距离哪些节点远了,那么以b在内的子树所有节点数量 c h i l d [ b ] child[b] child[b],到达b的距离相较于之前到达a的距离会减少1,而非b的子树节点数量 n − c h i l d [ b ] n-child[b] nchild[b]到达b的距离会都增加1

所以此时b到其他所有节点的距离就是 d i s t a n c e [ a ] + n − c h i l d [ b ] − c h i l d [ b ] . distance[a] + n-child[b] -child[b]. distance[a]+nchild[b]child[b].

因此首先就是通过边构建出树,然后计算出每个节点的子树节点数量,最后计算出每个节点的distance。

代码

public List<Integer>[] g;
    public int n;
    int[] ans,arr;
    public int[] sumOfDistancesInTree(int n, int[][] edges) {
        this.n = n;
        ans = new int[n];
        arr = new int[n];
        g = new ArrayList[n];
        for(int i =0;i<n;i++){
            g[i] =new ArrayList();
        }
        for(int[] e: edges){
            int x = e[0],y = e[1];
            g[x].add(y);
            g[y].add(x);
        }
        dfs(0,-1,0);
        reroot(0,-1);
        return ans;
    }

    public int dfs(int node,int fa,int d){
        int sum = 1;
        ans[0]+=d;
        List<Integer> child = g[node];
        for(int c: child){
            if(c==fa)continue;
            sum += dfs(c,node,d+1);
        }
        arr[node] = sum ;
        return sum;
    }
    public void reroot(int cur,int fa){
        List<Integer> child = g[cur];
        for(int c: child){
            if(c==fa)continue;
            ans[c] = ans[cur]+ n- 2*arr[c] ;
            reroot(c,cur );
        }
        return;
    }

时间复杂度 O ( N ) O(N) O(N)

空间复杂度 O ( N ) O(N) O(N)

Tag

Tree

DFS

Graph

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Eric.Cui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值