【算法】Distribute Coins in Binary Tree 在二叉树中分配硬币

文章目录

  • Distribute Coins in Binary Tree 在二叉树中分配硬币
    • 问题描述:
    • 分析
    • 代码
    • Tag

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个节点,ncoin,所以最终一定可以达到每个节点都有 1 个 c o i n 1个coin 1coin

问题就在于要使用什么方法来计算。

很明显当一个节点的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
  • 当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

DFS

你可能感兴趣的:(数据结构与算法,算法,java,数据结构)