979. Distribute Coins in Binary Tree

T: O(n)
S: O(n) 

็กฌๅธ็š„็งปๅŠจ่ง„ๅˆ™็œ‹ไผผๅพˆๅคๆ‚๏ผŒๅ› ไธบไธ€ไธช่Š‚็‚นๅฏ่ƒฝ้œ€่ฆ็งปๅ‡บ็กฌๅธ๏ผŒไนŸๅฏ่ƒฝ็งปๅ…ฅ็กฌๅธ๏ผŒ่ฟ˜่ฆๆฑ‚็งปๅŠจๆฌกๆ•ฐๆœ€ๅฐ‘ใ€‚ๅฎž้™…ไธŠๆˆ‘ไปฌ้œ€่ฆ่ง‚ๅฏŸ่ง„ๅพ‹๏ผŒๅšไธ€ไบ›็ญ‰ไปทใ€‚

ๅฆ‚ๆžœไธ€ไธช่Š‚็‚น็š„็กฌๅธไธชๆ•ฐๆ˜ฏ x๏ผŒๆ— ่ฎบๆ˜ฏ็งปๅ‡บ่ฟ˜ๆ˜ฏ็งปๅ…ฅ๏ผŒๆŠŠ่ฏฅ่Š‚็‚น็š„็กฌๅธไธชๆ•ฐๅ˜ๆˆ 1 ็š„ๆœ€ๅฐ‘็งปๅŠจๆฌกๆ•ฐๅฟ…็„ถๆ˜ฏ abs(x - 1)ใ€‚

ๅ‘็Žฐ่ฟ™ไธช่ง„ๅพ‹ๅŽ๏ผŒๅผ€ๅง‹ไบŒๅ‰ๆ ‘็š„้€š็”จ่งฃ้ข˜ๆ€่ทฏ๏ผšๅ‡ๆƒณไฝ ็Žฐๅœจ็ซ™ๅœจๆŸไธชๆ น่Š‚็‚นไธŠ๏ผŒไฝ ๅฆ‚ไฝ•็Ÿฅ้“ๆŠŠๅฝ“ๅ‰่ฟ™ๆฃตๅญๆ ‘็š„ๆ‰€ๆœ‰่Š‚็‚น้…ๅนณๆ‰€้œ€็š„ๆœ€ๅฐ็งปๅŠจๆฌกๆ•ฐ๏ผŸ

้‚ฃๅฐฑๅพˆ็ฎ€ๅ•ไบ†๏ผŒไฝ ๅ‡ๆƒณๅคšไฝ™็š„ๅ’Œ็ผบๅฐ‘็š„็กฌๅธ้ƒฝ็งปๅŠจๅˆฐๆ น่Š‚็‚นๅŽป้…ๅนณ๏ผŒๅฝ“็„ถๆ น่Š‚็‚นๆœฌ่บซไนŸ่ฆ้…ๅนณ๏ผŒๆ‰€ไปฅๆ•ดๆฃตๆ ‘้…ๅนณ็š„็งปๅŠจๆฌกๆ•ฐๅฐฑๆ˜ฏ๏ผš

// ่ฎฉๅฝ“ๅ‰่ฟ™ๆฃตๆ ‘ๅนณ่กกๆ‰€้œ€็š„็งปๅŠจๆฌกๆ•ฐ
Math.abs(left) + Math.abs(right) + (root.val - 1);
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int distributeCoins(TreeNode root) {
        int[] result = new int[1];
        dfs(root, result);
        return result[0];
    }
    private int dfs(TreeNode node, int[] result) {
        if (node == null) {
            return 0;
        }
        int left = dfs(node.left, result);
        int right = dfs(node.right, result);
        // System.out.println(left);
        // System.out.println(right);
        // System.out.println(Math.abs(left) + Math.abs(right) + node.val - 1);
        result[0] += Math.abs(left) + Math.abs(right) + node.val - 1; // move times, so need abs
        return left + right + node.val - 1;
    }
}

/***
ex:
  3 
 0. 
0

left = 0
right = 0
result += (Math.abs(left) + Math.abs(right) + node.val - 1) = 0 + 0 + (0-1) = -1
return -1

-> result[0] = -1;

left = -1
right = 0
result += (Math.abs(left) + Math.abs(right) + node.val - 1) = 1 + 0 + (0-1) = 0
return -2
-> result[0] = -1;

left = 2
right = 0
result += (Math.abs(left) + Math.abs(right) + node.val - 1) = 2 + 0 + (3-1) = 4
return 
 -> result[0] = -1 + 4 = 3;
 so 3 moves



T: O(n)
S: O(n) 


 */

Another easy thought:

class Solution {
    private record NodeInfo(int nodeCount, int coinSum){};
    public int distributeCoins(TreeNode root) {
        int[] result = new int[1];
        dfs(root, result);
        return result[0];
    }
    private NodeInfo dfs(TreeNode node, int[] result) {
        if (node == null) {
            return new NodeInfo(0, 0);
        }
        NodeInfo left = dfs(node.left, result);
        NodeInfo right = dfs(node.right, result);
        result[0] += Math.abs(left.nodeCount - left.coinSum) + Math.abs(right.nodeCount - right.coinSum);

        return new NodeInfo(left.nodeCount + right.nodeCount + 1, left.coinSum + right.coinSum + node.val);
    }
}

/***
idea: total moves = abs(subtree node count - suntree coin sum)

For each node, we record the information 
[# of nodes in the subtree (include itself), # of total coins in the subtree (include itself)]. 

Then we know that for a certain node, 
if there are more coins than nodes in the subtree, the node must "contribute" the redundant coins to its parent. 
Else, if there are more nodes than coins in the subtree, then the node must "take" some coins from the parent.

Both of these two operations will create moves in the tree. 
And we just need to add the absolute value of the (# nodes - # coins) to the final result 
because the move can be "contribute" or "take". 

The time complexity is O(n) because we are just traversing the tree.

ex:
  3 
 0. 
0

NodeInfo(1, 0)

result += 1;

NodeInfo(2, 0)

result += 2




T: O(n)
S: O(n) 


 */

Latest

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int distributeCoins(TreeNode root) {
        int[] result = new int[1];
        dfs(root, result);
        return result[0];
    }
    private int dfs(TreeNode node, int[] result) {
        if (node == null) {
            return 0;
        }
        int leftDiff = dfs(node.left, result);
        int rightDiff = dfs(node.right, result);
        int diff = leftDiff + rightDiff + node.val - 1;

        result[0] += Math.abs(diff);

        return diff;
    }
}

/***
T: O(n)
S: O(n)

we can only calculate moves based on the edge (from subtree to parent), with POST order
-> how many moves, moves = left_sub + right_sub + node.val - 1 (1 node count)


2 -> left child has diff -1, -1 +4 -1 = 2 -> 2 moves
  0
 / \ 1 -> means 1 moves
4   0
/ -> so means -1, one move
0. ex: this 0 needs 1 coin ((node.val - 1)) -> and left_sub (0) + right_sub(0) + (node.val - 1) = -1 (like borrow from parent 1 conis!)
so result = Math.abs(-1) = 1;
return this diff = -1 to upper rescursion

then in  4
 /
4
/
0
left_sub (-1) + right_sub(0) + (node.val - 1) = -1 + 0 + 4 - 1 = 2
so means this node will moves 2 to parent (1 coin already move to child (because left_sub is -1))
(result += math.abs(2)), result = 3

 0 
/ \
2 0 -> then here left_sub (0) + right_sub(0) + (node.val - 1) = -1 
(result += math.abs(-1)), result = 4

 0   -> left_sub (2) + right_sub(-1) + (node.val - 1) = 2 - 1 + 0 - 1 = 0 -> so no moves!
/ \
2 -1 


so result = 4 moves

in ths way, we accumulate from buttom to top, so there is no missing moves!
focus on distribute coins from buttom to top by diff(node val, node count and left_sub, right_sub)
 */

Last updated