在二叉树中分配硬币
https://leetcode.cn/problems/distribute-coins-in-binary-tree/description/
描述
给定一个有 N 个结点的二叉树的根结点 root,树中的每个结点上都对应有 node.val
枚硬币,并且总共有 N 枚硬币。
在一次移动中,我们可以选择两个相邻的结点,然后将一枚硬币从其中一个结点移动到另一个结点。(移动可以是从父结点到子结点,或者从子结点移动到父结点。)。
返回使每个结点上只有一枚硬币所需的移动次数。
示例
思路
一般二叉树解法以递归居多,精髓就是大事化小小事化了。这道题可以先从三个节点看起,如同上面框框所示,节点123要想达成平衡,需要移动几次?节点2有2个金币,节点3有4个,所以达成平衡需要节点2向节点1移动1个金币,也就是2-1,节点3需要向节点1移动3个金币,也就是4-1。所以现在总共移动了**(2-1)+(4-1)=4次**。
次数有了,为什么减1也知道,因为它要留一个,那怎么求这个2和4呢?
很简单,2或4=左子节点给它的+右子节点给它的+本身有的,左子节点给它的=另一个(2-1)或(4-1),所以我们设递归的关键函数dfs=func(node *TreeNode) int
返回值就是这个(2-1)或(4-1)
dfs = func(node *TreeNode) int {
var l, r int
if node == nil {
return 0
}
if node.Left != nil {
l = dfs(node.Left)
}
if node.Right != nil {
r = dfs(node.Right)
}
ans += abs(l) + abs(r) // 左右子节点可能是亏的 但是移动次数一定是正的
return l + r + node.Val - 1
}
最终代码如下
func distributeCoins(root *TreeNode) int {
var ans int
var dfs func(node *TreeNode) int
dfs = func(node *TreeNode) int {
var l, r int
if node == nil {
return 0
}
if node.Left != nil {
l = dfs(node.Left)
}
if node.Right != nil {
r = dfs(node.Right)
}
ans += abs(l) + abs(r)
return l + r + node.Val - 1
}
dfs(root)
return ans
}
func abs(i int) int {
if i < 0 {
return -i
}
return i
}