979. 在二叉树中分配硬币(Python)

难度:★★★☆☆
类型:树
方法:深度优先搜索

题目

力扣链接请移步本题传送门
更多力扣中等题的解决方案请移步力扣中等题目录

给定一个有 N 个结点的二叉树的根结点 root,树中的每个结点上都对应有 node.val 枚硬币,并且总共有 N 枚硬币。

在一次移动中,我们可以选择两个相邻的结点,然后将一枚硬币从其中一个结点移动到另一个结点。(移动可以是从父结点到子结点,或者从子结点移动到父结点。)。

返回使每个结点上只有一枚硬币所需的移动次数。

示例 1:

输入:[3,0,0]
输出:2
解释:从树的根结点开始,我们将一枚硬币移到它的左子结点上,一枚硬币移到它的右子结点上。

示例 2:

输入:[0,3,0]
输出:3
解释:从根结点的左子结点开始,我们将两枚硬币移到根结点上 [移动两次]。然后,我们把一枚硬币从根结点移到右子结点上。

示例 3:

输入:[1,0,2]
输出:2

示例 4:

输入:[1,0,0,null,3]
输出:4

提示:

1<= N <= 100
0 <= node.val <= N

解答

我们先给出定义几个名词:

【过载量】:一棵树上的金币总和超过结点数的金币数量。

【过载量的性质】:过载量可能为正,可能为负,也可能为零。当过载量为正时,金币总额分配给各个结点(每个结点一个金币)后仍有结余,当过载量负时,说明这棵树上的金币不足以分配给所有结点,当过载量为零时,说明金币总恰好可以分配给各个结点。

【过载量的计算】通过递归计算,左子树的过载量+右子树的过载量+根节点的过载量,其中根节点的过载量为该结点上金币的数量-1。这一个过程可以通过递归计算。

【过载量与移动次数的关系】针对一棵树的左右子树,它们过载的金币全部集中在各自的根节点上,换句话说,其他结点都已经各自分配好了一个金币,那么我们把这两个左右根节点上的过载金币全部转嫁到这棵树的根节点上,移动的次数就是这两个金币的过载量之和。

需要注意的是,过载量的正负在物理意义的表达上是一样的,在数值计算上需要取绝对值,因为过载量为负说明移动的方向和过载量为正时相反。

【编码】我们可以很容易的构建深度优先搜索函数,用于递归的实现过载量的计算。这个过程实际上是树的后续遍历过程,物理含义上,就是通过递归操作,逐层的将叶子节点的过载量向上级根节点集中,并在遍历过程中及时的计算每一层子树因过载造成的金币位移次数,并更新在总移动次数中,总次数需要作为全局变量 。

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


class Solution:
    def distributeCoins(self, root: TreeNode):
        self.ans = 0

        def dfs(r: TreeNode):

            if not r:
                return 0

            left = dfs(r.left)
            right = dfs(r.right)
            self.ans += abs(left) + abs(right)
            return r.val - 1 + left + right

        dfs(root)
        return self.ans

如有疑问或建议,欢迎评论区留言~

有关更多力扣中等题的python解决方案,请移步力扣中等题解析

你可能感兴趣的:(979. 在二叉树中分配硬币(Python))