美文网首页
手撕LeetCode #834——Python

手撕LeetCode #834——Python

作者: 烟花如雨旧故里 | 来源:发表于2020-10-23 13:44 被阅读0次

    834. 树中距离之和

    给定一个无向、连通的树。树中有 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,以此类推。
    

    解题思路:
    看上去这道题目很复杂,似乎要依次去求解每一个结点和树中其他结点的距离,时间复杂度至少都是O(N^2)。但仔细分析,我们还是能够找到规律的。

    首先我们先存储每个结点与它相连的结点记录:

    tree_link = [[] for _ in range(N)]
    for father, child in edges:
      tree_link[father].append(child)
      tree_link[child].append(father)
    

    题目已经告诉我们会有多少个结点(N), 那么可以先初始化两个数组来表示每个结点的深度和它的子结点数(包含它自己):

    depth = [0 for _ in range(N)]
    count = [1 for _ in range(N)]
    

    接下来,就是递归地去更新这两个数组:

    # grand表示父亲的父亲
    def get_Depth_Count(father, grand):
      # 遍历与父亲结点相连的结点
      for child in three_link[father]:
        # 如果该结点不是父亲的父亲结点,则表示该结点不是叶结点
        if child != grand:
          # 子结点的深度肯定比父结点深, +1
          depth[child] = depth[father] + 1
          # 继续往下更新子结点的深度
          get_Depth_Count(child, father)
          # 遍历完子结点后,将子结点的数量加到父结点上
          count[father] += count[child]
    

    最后,便是如何去具体地求解每一个结点与其他结点的距离,也就是我们要找的答案。我们先想一想,如果只是计算根结点与其他结点(也就是它的子结点)距离,结果就是将各个子结点的depth相加求和。好了,那我们再来看看其他结点的计算:


    结点2的距离

    我们看看在结点2处,它与根结点的距离是1,那它与子结点的距离就是根结点与2的子结点距离-1;同理,1结点与2结点的距离就是1结点与根结点的距离+1。那么规律就找到了:
    answer[2] = answer[0] + 与2同层结点数(不包括2) - 2的子结点数(包括2),因为我们已经知道总共N的结点,所以右边第二项可以改写为N-count[2]:
    answer[2] = answer[0] + N -2* (2的子结点数(包括2))
    根据树的子树递归性:
    求解公式可以写为:
    answer[child] = answer[father] + N -2* (child的子结点数(包括child))

    answer = [0 for _ in range(N)]
    answer[0] = sum(depth)
    def dfs(father, grand):
      for child in tree_link[father]:
        if child != grand:
          answer[child] = answer[father] + n - 2*count[child]
          dfs(child, father)
    
    dfs(0, -1)
    

    解题思路参考:

    「手画图解」树中距离之和 | 树形DP | 思路详解

    相关文章

      网友评论

          本文标题:手撕LeetCode #834——Python

          本文链接:https://www.haomeiwen.com/subject/zjjvmktx.html