thảo luận Leetcode mỗi ngày

JavaScript:
var removeLeafNodes = function(root, target) {
    function recursion(node) {
        if (!node) return false;

        if (node.left && recursion(node.left)) node.left = null;
        if (node.right && recursion(node.right)) node.right = null;

        return !node.left && !node.right && node.val === target;
    }

    if (recursion(root)) {
        return null;
    }

    return root;
};
 
Code:
class Solution {
public:
    TreeNode* removeLeafNodes(TreeNode*& root, int target) {
        if (!root)
            return root;
        removeLeafNodes(root->left, target);
        removeLeafNodes(root->right, target);
        if (!root->left && !root->right && root->val == target) {
            root = nullptr;
        }
        return root;
    }
};
 
Last edited:
C-like:
/**
 * Example:
 * var ti = TreeNode(5)
 * var v = ti.`val`
 * Definition for a binary tree node.
 * class TreeNode(var `val`: Int) {
 *     var left: TreeNode? = null
 *     var right: TreeNode? = null
 * }
 */
class Solution {
    fun removeLeafNodes(root: TreeNode?, target: Int): TreeNode? {
         if (root == null) {
            return null
        }
        root.left = removeLeafNodes(root.left, target)
        root.right = removeLeafNodes(root.right, target)
        return if (root.left == null && root.right == null && root.`val` == target) {
            null
        } else {
            root
        }
    }
}
 
C-like:
/**
 * Example:
 * var ti = TreeNode(5)
 * var v = ti.`val`
 * Definition for a binary tree node.
 * class TreeNode(var `val`: Int) {
 *     var left: TreeNode? = null
 *     var right: TreeNode? = null
 * }
 */
class Solution {
    fun removeLeafNodes(root: TreeNode?, target: Int): TreeNode? {
         if (root == null) {
            return null
        }
        root.left = removeLeafNodes(root.left, target)
        root.right = removeLeafNodes(root.right, target)
        return if (root.left == null && root.right == null && root.`val` == target) {
            null
        } else {
            root
        }
    }
}
:love:
 
Nhìn AC xong hí hửng, đọc đề xong ko có ý tưởng gì luôn đệt mẹ :ah:
Bài này giải bằng backtracking thì đơn giản cơ mà constrain này thì ko backtracking được rồi
 
Nhìn AC xong hí hửng, đọc đề xong ko có ý tưởng gì luôn đệt mẹ :ah:
Bài này giải bằng backtracking thì đơn giản cơ mà constrain này thì ko backtracking được rồi
Mỗi node 1 coin nên chỉ cần so sánh số coin nó hold với số nodes của mỗi sub tree là ra được số lượng move đến root của sub tree đó. Làm tương tự, đệ quy với các subtree nhỏ hơn. => Bài này chỉ cần viết đệ quy bt thôi

Python:
class Solution:
    def distributeCoins(self, root: Optional[TreeNode]) -> int:
        def dfs(node):
            if not node:
                return 0,0,0
            l_num_nodes, l_num_coins, l_num_move = dfs(node.left)
            r_num_nodes, r_num_coins, r_num_move = dfs(node.right)
            num_nodes = l_num_nodes + r_num_nodes + 1
            num_coins = l_num_coins + r_num_coins + node.val
            num_move = abs(l_num_nodes - l_num_coins) + abs(r_num_nodes - r_num_coins) + l_num_move + r_num_move
            return num_nodes, num_coins, num_move
        return dfs(root)[2]
 
Ae cho mình hỏi sao code này với code này lại cho kết quả khác nhau nhỉ, chỗ mình bôi đậm cho kết quả khác nhau, cái 1 ra kết quả đúng cái 2 lại ra kết quả sai :ah:
Input
nums1 =
[72,97,8,32,15]
nums2 =
[63,97,57,60,83]
Ngồi cả tiếng ko biết sao nó sai cay thật :ah: cái chỗ khác nhau là chỗ current ...ấy
À thường phép toán sẽ được ưu tiên phép bitwise, phải để ý mới được ko bug sml
Python:
class Solution:
    def minimumXORSum(self, nums1: List[int], nums2: List[int]) -> int:
        n = len(nums1)

        @lru_cache(None)
        def dp(i, mask):
            if i == n:
                return 0
         
            ans = inf
            for j in range(n):
                if (mask >> j) & 1 == 0:
                    current = nums1[i]^nums2[j]
                    ans = min(ans, current + dp(i + 1, mask|(1 << j)))

            return ans

        return dp(0, 0)
Python:
class Solution:
    def minimumXORSum(self, nums1: List[int], nums2: List[int]) -> int:
        n = len(nums1)

        @lru_cache(None)
        def dp(i, mask):
            if i == n:
                return 0
         
            ans = inf
            for j in range(n):
                if (mask >> j) & 1 == 0:
                    ans = min(ans, nums1[i]^nums2[j] + dp(i + 1, mask|(1 << j)))

            return ans

        return dp(0, 0)
 
Last edited:
Mỗi node 1 coin nên chỉ cần so sánh số coin nó hold với số nodes của mỗi sub tree là ra được số lượng move đến root của sub tree đó. Làm tương tự, đệ quy với các subtree nhỏ hơn. => Bài này chỉ cần viết đệ quy bt thôi

Python:
class Solution:
    def distributeCoins(self, root: Optional[TreeNode]) -> int:
        def dfs(node):
            if not node:
                return 0,0,0
            l_num_nodes, l_num_coins, l_num_move = dfs(node.left)
            r_num_nodes, r_num_coins, r_num_move = dfs(node.right)
            num_nodes = l_num_nodes + r_num_nodes + 1
            num_coins = l_num_coins + r_num_coins + node.val
            num_move = abs(l_num_nodes - l_num_coins) + abs(r_num_nodes - r_num_coins) + l_num_move + r_num_move
            return num_nodes, num_coins, num_move
        return dfs(root)[2]
Hay quá fence, mình nghĩ ko ra xem solution luôn rồi :ah:
 
Java:
class Solution {
    public int[] divideAndConquer(TreeNode root) {
        if (root == null)
            return new int[]{0, 1};
        int[] lt = divideAndConquer(root.left);
        int[] rt = divideAndConquer(root.right);
        int[] res = new int[2];
        int leftVal = root.left == null ? 1 : root.left.val;
        int rightVal = root.right == null ? 1 : root.right.val;
        res[0] = lt[0] + rt[0] + Math.abs(lt[1] - leftVal) + Math.abs(rt[1] - rightVal);
        res[1] = lt[1] + rt[1] - leftVal - rightVal + 1;
        return res;
    }

    public int distributeCoins(TreeNode root) {
        int[] res = divideAndConquer(root);
        return res[0];
    }
}

Bài này thấy tiệm cận hard rồi, mà accept rate cao quá
 
Bài này chắc toàn mấy thằng thấy AC cao quá vào làm, rồi thấy khó quá ko làm được thì đi copy paste submit -> AC tiếp tục cao nữa
FInxYfK.png
 
nếu dfs return giá trị âm tức là node con xin value từ bên trên, dfs dương tức là node con chia coin cho node bên trên, + hay - thì đều tốn từng ấy bước để chia cho node khác
giống y chang cách trong editorial lun :big_smile:
Java:
class Solution {
    int move =0;
    public int distributeCoins(TreeNode root) {
        dfs(root);
        return move;
    }
    private int dfs(TreeNode node){
        if(node == null ) return 0;
        int left =dfs(node.left);
        int right=dfs(node.right);
        move+= Math.abs(left);
        move+= Math.abs(right);
        return node.val - (1-left-right) ;
    }
}
chơi cheat 1 tí dùng biến global để xử lí chứ java ko biết lấy giá trị bên trong ra ntn
 
Last edited:
  • Đếm tổng số transfer đi ra và transfer đi vào tại mỗi phần tử của cây. Nếu một nhánh con dư coin thì phải transfer phần dư vào trong cha, nếu thiếu coin thì phải transfer ra từ cha vào nhánh đó.
  • Ý tưởng này cũng có phần tương đồng với cách phân tích complexity cho thuật toán DFS, nếu đọc Cormen et al. thì họ gọi là "aggregate analysis". Trong toàn vòng đời của thuật toán mỗi bước chạy ít nhất là bao nhiêu, tối đa là bao nhiêu lần?
Ruby:
def distribute_coins(root)
    node_count_tree = node_count(root)
    coin_count_tree = coin_count(root)

    distribute_coins_helper(root, node_count_tree, coin_count_tree)
end

def distribute_coins_helper(node, node_count_tree, coin_count_tree)
    transfer_count = 0

    if node.left
        transfer_count += (coin_count_tree.left.val - node_count_tree.left.val).abs
        transfer_count += distribute_coins_helper(node.left, node_count_tree.left, coin_count_tree.left)
    end

    if node.right
        transfer_count += (coin_count_tree.right.val - node_count_tree.right.val).abs
        transfer_count += distribute_coins_helper(node.right, node_count_tree.right, coin_count_tree.right)
    end

    transfer_count
end

def node_count(node)
    return nil if node.nil?

    left = node_count(node.left)
    right = node_count(node.right)

    TreeNode.new(
        (left&.val || 0) + (right&.val || 0) + 1,
        left,
        right
    )
end

def coin_count(node)
    return nil if node.nil?

    left = coin_count(node.left)
    right = coin_count(node.right)

    TreeNode.new(
        (left&.val || 0) + (right&.val || 0) + node.val,
        left,
        right
    )
end


Ruby:
def distribute_coins(node)
    _, _, transfers = distribute_coins_helper(node)

    transfers
end

def distribute_coins_helper(node)
    return [0, 0, 0] if node.nil?

    left_count, left_coins, left_transfers = distribute_coins_helper(node.left)
    right_count, right_coins, right_transfers = distribute_coins_helper(node.right)

    return [
        left_count + right_count + 1,
        left_coins + right_coins + node.val,
        left_transfers + right_transfers + (left_coins - left_count).abs + (right_coins - right_count).abs
    ]
end
 
Last edited:
Code:
object Solution {
  def distributeCoins(root: TreeNode): Int = {
    val (_, moves) = dfs(root)
    moves
  }
 
  def dfs(node: TreeNode): (Int, Int) = {
    if (node == null) (0, 0)
    else {
      val (leftExcess, leftMoves) = dfs(node.left)
      val (rightExcess, rightMoves) = dfs(node.right)
      
      val totalExcess = node.value + leftExcess + rightExcess - 1
      val totalMoves = leftMoves + rightMoves + Math.abs(leftExcess) + Math.abs(rightExcess)
      
      (totalExcess, totalMoves)
    }
  }
}
 
Python:
class Solution:
    def distributeCoins(self, root: Optional[TreeNode]) -> int:
        moves = 0 
        def distribute(root):
            if not root:
                return 0
                
            nonlocal moves
            leftCoins = distribute(root.left)
            rightCoins = distribute(root.right)
            moves += abs(leftCoins) + abs(rightCoins)
            return leftCoins + rightCoins + root.val - 1
        
        distribute(root)
        return moves

Bài hôm nay hay quá, ngồi ngâm cả tiếng tìm cách dp gom nhóm đồ vẫn ko nghĩ ra cách nào pass được limit. Cuối cùng phải xem editorial :shame:.
2 bài similar questions nhìn cũng cuốn phết.
 
19/05/2024: bài hôm nay từng làm rồi. Bài này khá là tricky, có thể giải mà k cần dựa vào tree.
Python:
class Solution:
    def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int:
        ret, count_xor, diff = 0, 0, inf
        for num in nums:
            num_xor = num ^ k
            ret += max(num, num_xor)
            count_xor += int(num_xor > num)
            diff = min(diff, abs(num - num_xor))
        return ret if count_xor%2 == 0 else ret - diff
 
Back
Top