You are given the root
of a binary tree with n
nodes where each node
in the tree has node.val
coins. There are n
coins in total throughout the whole tree.
In one move, we may choose two adjacent nodes and move one coin from one node to another. A move may be from parent to child, or from child to parent.
Return the minimum number of moves required to make every node have exactly one coin.
Example 1:
Input: root = [3,0,0] Output: 2 Explanation: From the root of the tree, we move one coin to its left child, and one coin to its right child.
Example 2:
Input: root = [0,3,0] Output: 3 Explanation: From the left child of the root, we move two coins to the root [taking two moves]. Then, we move one coin from the root of the tree to the right child.
Constraints:
- The number of nodes in the tree is
n
. 1 <= n <= 100
0 <= Node.val <= n
- The sum of all
Node.val
isn
.
题目给定一棵二叉树具有n个节点,每个节点值node.val表示该节点所拥有的硬币数。硬币总数为n,也就是说有的节点可能超过一枚硬币,有的节点可能没有硬币,现在要求通过移动硬币使得最后每个节点都刚好拥有一枚硬币。每次移动只能从一个节点移动到其相连的节点(父节点,左子节点或右子节点),并且一次只能移动一枚硬币。问最少需要移动几次可以使得每个节点都有一枚硬币?
为了使移动次数要最少,基本原则就是使移入或移出一个节点的硬币数要刚刚好。对于一个节点,它可以把整棵树分成2个部分:1)以该节点为根节点的子树;2)该节点的父节点以上的其它部分。经过该节点的进入或流出子树的硬币数,取决于子树里硬币的总数,如果硬币总数少于节点总数意味着要从外部输入硬币,反之如果硬币总数大于节点总数意味着有多余的硬币可以输出给其他地方使用。但是不管是输入还是输出,对于该节点来说都是硬币的移动。节点上多余或缺少的硬币数又由其自身加上左子树和右子树决定,假定左右子树多余或缺少硬币数分别为lcnt和rcnt(lcnt和rcnt为正表示有多余硬币,为负表示缺少硬币),另外节点本身始终需要一枚硬币,那么最终该节点上硬币数为node.val - 1 + lcnt + rcnt,也就是对于该节点最少移动次数。(值为负就去绝对值)。由于叶节点没有左右子树,一开始是否多余或缺少硬币就已经确定了,因此本可以通过递归从底向上计算每个节点上所需硬币数。
class Solution:
def distributeCoins(self, root: Optional[TreeNode]) -> int:
res = 0
def helper(node):
if not node:
return 0
lcnt = helper(node.left)
rcnt = helper(node.right)
cnt = node.val - 1 + lcnt + rcnt
nonlocal res
res += abs(cnt)
return cnt
helper(root)
return res