Distribute Coins in Binary Tree 在二叉树中分配硬币
问题描述:
给定一个有 N 个结点的二叉树的根结点 root,树中的每个结点上都对应有 node.val 枚硬币,并且总共有 N 枚硬币。
在一次移动中,我们可以选择两个相邻的结点,然后将一枚硬币从其中一个结点移动到另一个结点。(移动可以是从父结点到子结点,或者从子结点移动到父结点。)。
返回使每个结点上只有一枚硬币所需的移动次数。
1 < = N < = 100 0 < = n o d e . v a l < = N 1 <= N <= 100\\ 0 <= node.val <= N 1<=N<=1000<=node.val<=N
分析
有n个节点,每个节点上有值,并且表示该节点的coin数量。
一个coin移动到相邻的节点,就是一次移动。
目标就是求每个节点都有1个coin的时候,移动的次数。
一共有
n
个节点,
n
个
c
o
i
n
n个节点,n个coin
n个节点,n个coin,所以最终一定可以达到每个节点都有
1
个
c
o
i
n
1个coin
1个coin。
问题就在于要使用什么方法来计算。
很明显当一个节点的coin>1的时候,说明多出来的就需要分出去。而coin=0的时候,就需要进来一个。
但是以一个节点为角度观察,当多出来的coin,需要出去,那么应该去父节点,还是子节点,同时coin的去向还要考虑到相邻的节点是否需要。
以最简单的情况思考当 p是leaf node.
- 如果p.val>1,说明此时,多出来的一定要给父节点。
- 而p.val=0,此时父节点必须给p一个coin。
- 当 p . v a l = = 1 p.val==1 p.val==1,p作为叶子,是不需要做任何处理的,对整体计算结果无影响。
如果p不是叶子,并且p作为一个子树的root,包含p在内有m个节点,同时p为root的子树上的coins总数为cnt。
- 当m==cnt时,说明p上的coin可以完全分配到p子树的所有节点,不需要上交,也不需要额外的节点。
- 当m<cnt,说明p的子树要达到完全分配,就必须上交cnt-m个coin。
- 当m>cnt,说明p的子树要达到完全分配,就必须有父节点给它m-cnt个coin。
到此可以总结一个规律:
可以确定的一点,在p的父节点和p的路径上,必然要有abs(m-cnt)的coin移动一次。而且不需要关心节点的最终目标在哪里。
除了root节点,每个节点都与父节点有一个路径,即n-1条。
那么对每个节点都进行一次计算,就可以得到coin在每一个路径移动的次数。
设计一个dfs(root),返回root为根节点的子树,2个值{子树的总结点数,子树的总coins数}
代码
int ans=0;
public int distributeCoins(TreeNode root) {
dfs(root);
return ans;
}
public int[] dfs(TreeNode root){
if(root==null) return new int[]{0,0};
int[] cnt = new int[]{root.val,1};
int[] left = dfs(root.left);
int[] right = dfs(root.right);
cnt[1]+= left[1]+right[1];
cnt[0]+= left[0]+right[0];;
ans+= Math.abs(cnt[1]-cnt[0]);
return cnt;
}
时间复杂度 O ( N ) O(N) O(N)
空间复杂度 O ( N ) O(N) O(N)
Tag
Tree
文章来源:https://www.toymoban.com/news/detail-565322.html
DFS
文章来源地址https://www.toymoban.com/news/detail-565322.html
到了这里,关于【算法】Distribute Coins in Binary Tree 在二叉树中分配硬币的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!