JavaInterview JavaInterview
首页
指南
分类
标签
归档
  • CSDN (opens new window)
  • 文档集合 (opens new window)
  • 系统架构 (opens new window)
  • 微信号 (opens new window)
  • 公众号 (opens new window)

『Java面试+Java学习』
首页
指南
分类
标签
归档
  • CSDN (opens new window)
  • 文档集合 (opens new window)
  • 系统架构 (opens new window)
  • 微信号 (opens new window)
  • 公众号 (opens new window)
  • 指南
  • 简历

  • Java

  • 面试

  • 算法

  • algorithm
  • leetcode
JavaInterview.cn
2022-09-02
目录

树中距离之和Java

文章发布较早,内容可能过时,阅读注意甄别。

# 题目

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

给定整数 n 和数组 edges , edges[i] = [ai, bi]表示树中的节点 ai 和 bi 之间有一条边。

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

示例 1:

输入: n = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]]
输出: [8,12,6,10,10,10]
解释: 树如图所示。
我们可以计算出 dist(0,1) + dist(0,2) + dist(0,3) + dist(0,4) + dist(0,5) 
也就是 1 + 1 + 2 + 2 + 2 = 8。 因此,answer[0] = 8,以此类推。

示例 2:

输入: n = 1, edges = []
输出: [0]

示例 3:

输入: n = 2, edges = [[1,0]]
输出: [1,1]

提示:

  • 1 <= n <= 3 * 104
  • edges.length == n - 1
  • edges[i].length == 2
  • 0 <= ai, bi < n
  • ai != bi
  • 给定的输入保证为有效的树

# 思路

dfs

# 解法


class Solution {
    
    public int[] sumOfDistancesInTree(int N, int[][] edges) {
        int[] result = new int[N];//最终结果存放处
        ArrayList<Node> nodeList = new ArrayList<Node>(N);
        for (int i = 0; i < N; i++) {
            nodeList.add(new Node(i));
        }
        for (int i = 0; i < edges.length; i++) {
            int a = edges[i][0];
            int b = edges[i][1];
            Node nodeA = nodeList.get(a);
            Node nodeB = nodeList.get(b);
            nodeA.link(nodeB);
        }
        Node root = nodeList.get(0);
        root.traverse();//建立以0节点为根节点的一棵树
        root.initiate();//计算0节点的各种距离 递归先算子树距离
        root.totalDistance = root.subDistance; 
        root.calculateDistance(N);//换根 用状态转移公式 dfs遍历
        //存储结果:
        for (int i = 0; i < N; i++) {
            result[i] = nodeList.get(i).totalDistance;
        }
        return result;
    }

    class Node {
        int val;
        Node parent;//父节点
        List<Node> nodes;//邻接节点
        int size;//以nodes为根的树有多少节点(包括本身)
        boolean visited;
        int subDistance;
        int totalDistance;
        public Node(int val) {
            this.val = val;
            this.parent = null;
            this.nodes = new ArrayList<Node>();
            this.size = 1;
            this.visited = false;
            this.subDistance = 0; //以该节点为子树包含的距离
            this.totalDistance = 0; //该节点的最终结果
            // 对于0节点 两个距离最后计算完了会相等
            // 对于0以外的节点 totalDistance都是通过其他节点的totalDistance进行状态转换得来的
            // 0以外的节点,totalDistance和subDistance不同
        }

        // 将本节点与anotherNode节点连接起来 
        // 连接是双向的 即同时建立两条无向边
        public void link(Node anotherNode) {
            this.nodes.add(anotherNode);
            anotherNode.nodes.add(this);
        }

        // 从node开始 dfs遍历
        // 一边遍历一边移除根节点 防止遍历的时候返回去
        public void traverse() {
            for (Node node: nodes) {
                node.parent = this; //邻接节点的父节点指向当前节点 表示是从当前节点来的
                node.nodes.remove(this);// 一边遍历一边移除根节点 防止遍历的时候返回去
                node.traverse(); //dfs递归
            }
        }

        // 遍历统计子树的信息
        public void initiate() {
            for (Node node: nodes) {
                node.initiate();
                this.size += node.size; //更新节点数=已有节点数+子树节点数
                this.subDistance += node.subDistance;//更新距离=已有距离+子树距离
                this.subDistance += node.size;//更新距离=已有距离+子树节点数
                // 因为每一个子树节点连接到当前节点还要再多一条线
            }
        }

        // 状态转移 对邻接节点换根 dfs遍历
        public void calculateDistance(int N) {
            // 遍历时并不会遍历到本节点的根节点 这个问题已经在traverse()里面解决了
            for (Node node: nodes) {
                // 状态转移方程 计算node节点的最终结果
                node.totalDistance = this.totalDistance + N - node.size * 2;
                // dfs遍历node的邻接节点
                node.calculateDistance(N);
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

# 总结

  • 分析出几种情况,然后分别对各个情况实现
微信 支付宝
最近更新
01
1686. 石子游戏VI Java
08-18
02
1688. 比赛中的配对次数 Java
08-18
03
1687. 从仓库到码头运输箱子 Java
08-18
更多文章>
Theme by Vdoing | Copyright © 2019-2025 JavaInterview.cn
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式