【每日一题Day265】LC979在二叉树中分配硬币 | 树形dp

文章介绍了如何解决LeetCode上的979题,即在二叉树中分配硬币,使得每个节点恰好拥有一枚硬币。通过使用深度优先搜索(DFS)和树形动态规划(TreeDP)的方法,计算每个子树的硬币总数和节点数,进而确定需要移动的硬币数,最终求出最小移动次数。文章提供了两种解决方案,一种是直接计算每条边经过的硬币差值,另一种是优化后的计算方式,减少计算量,两者均具有O(n)的时间复杂度。

在二叉树中分配硬币【LC979】

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

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

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

好巧妙 没想出来

  • 思路:

    • 移动的次数可以视为所有边经过的金币数的累加和,如果某子树的金币数目coinscoinscoins等于节点数目nodesnodesnodes,那么不需要进行移动;否则,一定有硬币需要向上或者向下移动,该边经过的金币数目为∣coins−nodes∣|coins-nodes|coinsnodes
    • 故该问题可以用树形dp解决,dfs返回每颗子树的金币数目和节点数目,计算每条边经过的金币数,累加返回结果
  • 实现

    class Solution {
        private int ans;
    
        public int distributeCoins(TreeNode root) {
            dfs(root);
            return ans;
        }
    
        private int[] dfs(TreeNode node) {
            if (node == null)
                return new int[]{0, 0};
            var left = dfs(node.left);
            var right = dfs(node.right);
            int coins = left[0] + right[0] + node.val; // 子树硬币个数
            int nodes = left[1] + right[1] + 1; // 子树节点数
            ans += Math.abs(coins - nodes);
            return new int[]{coins, nodes};
        }
    }
    
    作者:灵茶山艾府
    链接:https://leetcode.cn/problems/distribute-coins-in-binary-tree/solutions/2343262/tu-jie-mei-you-si-lu-jin-lai-miao-dong-p-vrni/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    • 复杂度
      • 时间复杂度:O(n)\mathcal{O}(n)O(n)
      • 空间复杂度:O(n)\mathcal{O}(n)O(n)
  • 优化:

    整理可得:
    d=coins−nodes=(coinsleft+coinsright+node.val)−(nodesleft+nodesright+1)=(coinsleft−nodesleft)+(coinsright−nodesright)++node.val−1=dleft+dright+node.val−1 d=coins−nodes\\ = (coins_{left}+coins_{right}+node.val)−(nodes_{left}+nodes_{right}+1)\\ =(coins_{left}-nodes_{left})+(coins_{right}-nodes_{right})++node.val-1\\ =d_{left}+d_{right} +node.val−1 d=coinsnodes=(coinsleft+coinsright+node.val)(nodesleft+nodesright+1)=(coinsleftnodesleft)+(coinsrightnodesright)++node.val1=dleft+dright+node.val1

    class Solution {
        private int ans;
    
        public int distributeCoins(TreeNode root) {
            dfs(root);
            return ans;
        }
    
        private int dfs(TreeNode node) {
            if (node == null)
                return 0;
            int d = dfs(node.left) + dfs(node.right) + node.val - 1;
            ans += Math.abs(d);
            return d;
        }
    }
    
    作者:灵茶山艾府
    链接:https://leetcode.cn/problems/distribute-coins-in-binary-tree/solutions/2343262/tu-jie-mei-you-si-lu-jin-lai-miao-dong-p-vrni/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    • 复杂度
      • 时间复杂度:O(n)\mathcal{O}(n)O(n)
      • 空间复杂度:O(n)\mathcal{O}(n)O(n)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值