Leetcode Daily Question 23/10/2024 - 2641. Cousins in Binary Tree II

Problem Description:

Given the root of a binary tree, replace the value of each node in the tree with the sum of all its cousins' values. | ------------------------------------------------------------ | Two nodes of a binary tree are cousins if they have the same depth with different parents. | ------------------------------------------------------------ | Return the root of the modified tree. | ------------------------------------------------------------ | Note that the depth of a node is the number of edges in the path from the root node to it.

Solution:

from typing import Optional
class TreeNode:
  def __init__(self, val = 0, left = None, right = None):
    self.val = val
    self.left = left
    self.right = right
    

class Solution:
  def replaceValueInTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
    if not root:
      return None
    
    queue = deque([root])
    level_sums = []
    
    while queue:
      level_size = len(queue)
      level_sum = 0
      for _ in range(level_size):
        node = queue.popleft()
        level_sum += node.val
        if node.left:
          queue.append(node.left)
        if node.right:
          queue.append(node.right)
      level_sums.append(level_sum)
      
      
    depth = 1
    nqueue = deque([root])
    root.val = 0
    
    while nqueue:
      level_size = len(nqueue)
      for _ in range(nqueue):
        node = nqueue.popleft()
        sib_sum = (node.left.val if node.left else 0) + (node.right.val if node.right else 0)
        if node.left:
          node.left.val = level_sums[depth] - sib_sum
          nqueue.append(node.left)
        if node.right:
          node.right.val = level_sums[depth] - sib_sum
          nqueue.append(node.right)
      depth += 1
        
    return root

Explanation:

The idea is use BFS twice. Once to calculate the level sum for each level of the tree. Once to update the values of the nodes base on its siblings (nodes with same parents).

Lets start by calculating the level sums.

queue = deque([root])
level_sums = []

while queue:
  level_size = len(queue)
  level_sum = 0
  for _ in range(level_size):
    node = queue.popleft()
    level_sum += node.val
    if node.left:
      queue.append(node.left)
    if node.right:
      queue.append(node.right)
  level_sums.append(level_sum)

Since every node can only have a maximum of two children, it follows that every node can have at most one sibling.

So if we know the level sum, we can calculate the value of the node by subtracting the sibling sum (the node itself + its sibling if exists) from the level sum.

nqueue = deque([root])
depth = 1 # We are adjusting the value of children, so we need the next level.
root.val = 0 # Root has no parent, so it cannot have any siblings / cousins.

while nqueue:
  level_size = len(nqueue)
  for _ in range(level_size):
    node = nqueue.popleft()
    sib_sum = (node.left.val if node.left else 0) + (node.right.val if node.right else 0)
    if node.left:
      node.left.val = level_sums[depth] - sib_sum
      nqueue.append(node.left)
    if node.right:
      node.right.val = level_sums[depth] - sib_sum
      nqueue.append(node.right)
  depth += 1

return root

The time complexity is O(n). We visit each node twice with the two bfs traversal. So time complexity is O(2n) ≈ O(n)

The space complexity is O(n), as we store the sum of each level. There can be at most n levels for n nodes.

The full solution can be found near the top of the page.

Back