• recategorized by
473 views
2 2 votes

In a binary tree $T$, for a node $v$, the $\text{LEFT-HEIGHT} (v)$ is the length of the longest path from $v$ to any leaf in the left subtree of $v$. If $v$ has no left child then $\text{LEFT-HEIGHT} (v)=0$. The $\text{RIGHT-HEIGHT} (v)$ is defined accordingly.

A node $v$ is said to be properly balanced if $$ \mid \operatorname{LEFT-HEIGHT}(v)-\text { RIGHT-HEIGHT }(v) \mid \leq 1 \text {. } $$ Design an efficient algorithm that, given a binary tree, enumerates all the nodes which are properly balanced.

1 Answer

0 0 votes

A node \( v \) in a binary tree is defined as properly balanced if the absolute difference between its left height and right height is at most 1, i.e., 

\[ |\text{LEFT-HEIGHT}(v) - \text{RIGHT-HEIGHT}(v)| \leq 1 \] 

Our goal is to identify all such nodes efficiently, ideally in \( O(n) \) time, where \( n \) is the number of nodes in the tree.

Bottom-Up Height Computation

Since we need to determine the left and right heights for every node and check the balance condition, a naive approach—computing heights from scratch for each node—would take \( O(n) \) time per node, leading to an \( O(n^2) \) algorithm. 😕

To achieve efficiency, we can compute heights in a bottom-up manner using a post-order traversal. In a post-order traversal, we process a node’s left child, then its right child, and finally the node itself. This allows us to compute the height of a subtree once and reuse it when evaluating the parent node.😀

Algorithm Design and Plannig 

We can design a recursive algorithm that:
1. Computes the height of each subtree rooted at a node.
2. Uses these heights to check the balance condition at each node.
3. Collects all nodes that are properly balanced.   Simple 😉

NOTE: The height of a subtree rooted at a node is defined as the length of the longest path from that node to a leaf in its subtree, which is 1 plus the maximum of the left and right heights (or 0 if the node is a leaf or NULL). For a NULL node (no subtree), the height is 0, match with  problem’s convention that the height is 0 when there is no child.

To enumerate the balanced nodes, we can accumulate them in a list during the traversal. We’ll use a recursive function that returns the height of the subtree and, as a side effect, appends properly balanced nodes to a shared list.

- Input: A binary tree \( T \) with a root node.
- Output: A list of all nodes in \( T \) that are properly balanced.
- Data Structure: A list `balanced_nodes` to store the properly balanced nodes, accessible across recursive calls.

Procedure
1. Initialize an empty list `balanced_nodes`.
2. Call `computeHeightAndCheckBalance(root, balanced_nodes)` recurssive function on the root of the tree \( T \).

  • which use a post-order traversal to compute the heights of the left and right subtrees for each node.
  • For each node, checking if the absolute difference between its left height and right height is less than or equal to 1.
  • Collect the nodes that satisfy this condition in a list during the traversal.

3. After the call completes, `balanced_nodes` contains all properly balanced nodes.
4. Return or process `balanced_nodes` as needed 

 

// Recursive function to compute height and check balance
int computeHeightAndCheckBalance(node, balanced_nodes) 
{
    // Base case: empty subtree
    if (node == NULL) {
        return 0
    }

    // Recursively compute left height
    left_height = computeHeightAndCheckBalance(node->left, balanced_nodes)
    
    // Recursively compute right height
    right_height = computeHeightAndCheckBalance(node->right, balanced_nodes)
    
    // Check if the node is properly balanced
    if (abs(left_height - right_height) <= 1) {
        addBalancedNode(balanced_nodes, node)
    }
    
    // Compute the height of the current node
    height = 1 + (left_height > right_height ? left_height : right_height)
    
    return height
}


// Add a node to the balanced nodes list
void addBalancedNode(list,  node) 
{
    if (list->count >= list->capacity) 
    {
        // Simple handling: in practice, resize the array
        print("Balanced nodes array is full!\n")
        return;
    }
    list->nodes[list->count] = node;
    list->count++;
}

 

Complexity Analysis

Time Complexity: The algorithm performs a post-order traversal, visiting each node exactly once. At each node, it performs constant-time operations: two recursive calls (processed once per node), a balance check, and possibly appending to the list. Thus, the total time is \( O(n) \), where \( n \) is the number of nodes.
Space Complexity:  The recursion stack depth is equal to the height of the tree, which is \( O(h) \), where \( h \) is the tree’s height. In the worst case (e.g., a skewed tree), \( h = n \), so \( O(n) \).

  •   The `balanced_nodes` list stores up to \( n \) nodes, requiring \( O(n) \) space.
  •   Total space complexity is \( O(n) \).
Position:
Show:

Related questions

2 2 votes
2 2 answers
887
887 views
admin asked Aug 8, 2022
887 views
Consider a stack machine where the only available workspace is a stack whose elements are unsigned integers. We will denote the configuration of the stack by a sequence. ...
1 1 vote
1 1 answer
387
387 views
admin asked Aug 8, 2022
387 views
The following function computes an array $\textsf{SPF},$ where, for any integer $1<1<1000, \textsf{SPF[i]}$ is the smallest prime factor of $\textsf{i}.$ For example, $\t...
1 1 vote
1 1 answer
380
380 views
admin asked Aug 8, 2022
380 views
Let $R$ be a relation with functional dependencies $\mathcal{F}$. For any subset of attributes $X \subseteq R$, the closure of $X$ is defined as the set$$ X^{+}=\{A \in R...
0 0 votes
0 0 answers
221
221 views
admin asked Aug 8, 2022
221 views
An $n$-variable Boolean function $f:\{0,1\}^{n} \rightarrow\{0,1\}$ is called symmetric if its value depends only on the number of $1 \text{'s}$ in the input. Let $\sigma...