Populating Next Right Pointers in Each Node II

Updated on 30 June, 2025
Populating Next Right Pointers in Each Node II header image

Problem Statement

In the task, you are given a binary tree where each node contains an additional pointer, next, initially set to NULL. The objective is to modify the tree so that each node's next pointer points to its next right node in the same level. If there is no node on the right, the next pointer should remain NULL. The structure of a node in the binary tree is defined as:

struct Node {
    int val;
    Node *left;
    Node *right;
    Node *next;
}

For illustration, the tree is represented level-by-level. When there is no node to the right at the same level for a particular node, its next pointer should point to NULL. This adjustment allows one to traverse the tree using next pointers level by level.

Examples

Example 1

Input:

root = [1,2,3,4,5,null,7]

Output:

[1,#,2,3,#,4,5,7,#]

Explanation:

Given the tree:
       1
     /   \
    2     3
   / \     \
  4   5     7

After connecting next pointers:
1 → NULL  
2 → 3 → NULL  
4 → 5 → 7 → NULL  

Serialized using next pointers as [1,#,2,3,#,4,5,7,#]

Example 2

Input:

root = []

Output:

[]

Explanation:

The input is an empty tree, so no connections are made and output remains empty.

Constraints

  • The number of nodes in the tree is in the range [0, 6000].
  • -100 <= Node.val <= 100

Approach and Intuition

The task requires linking each node to its immediate right sibling at the same level. Let's break down the approach:

  1. Level-wise Traversal:

    • Traverse the tree level-by-level using Breadth-First Search (BFS). Use a queue to process each level in order.
  2. Linking Neighbors:

    • For each node at the current level, set its next pointer to the next node in the level (from the queue), or NULL if it's the last node in that level.
  3. Using a Queue for BFS:

    • Enqueue each node’s children—left first, then right.
    • For every level, process all nodes and set their next pointers accordingly.
  4. Edge Cases:

    • If the root is NULL, return NULL directly without processing.

This BFS-based approach guarantees that each level of the tree is handled correctly and efficiently. It ensures the next pointers form horizontal links across nodes at the same level, enabling a streamlined and connected tree traversal experience.

Solutions

  • C++
  • Java
  • C
  • JavaScript
  • Python
cpp
class Solution {
    Node* previous = NULL;
    Node* first = NULL;
    
    void handleChild(Node* child) {
        if (child) {
            if (previous) {
                previous->next = child;
            } else {
                first = child;
            }
            previous = child;
        }
    }
    
public:
    Node* connect(Node* root) {
        if (!root) {
            return root;
        }
        first = root;
        Node* current = first;
    
        while (first) {
            previous = NULL;
            current = first;
            first = NULL;
    
            while (current) {
                handleChild(current->left);
                handleChild(current->right);
                current = current->next;
            }
        }
        return root;
    }
};

The solution provided is designed to address the classic problem of modifying a binary tree structure such that each node's next pointer points to the next right node within the same level. If there is no node on the right, the next pointer should be set to NULL. This implementation works for a binary tree where not all nodes have two children, which adds complexity to the traversal and linkage compared to a perfect binary tree, where every node has exactly two children or none.

This C++ implementation uses an extra pointer to efficiently link nodes at each level without requiring additional data structures such as a queue which is commonly used for level-order traversal. The approach operates directly on the tree nodes themselves by maintaining three pointers:

  • previous: This tracks the last node we've processed at the current level, helping link it with the next node.
  • first: This is set to the leftmost node of the next level to handle in the next while loop iteration.
  • current: Used for navigating through the nodes at the current level.

The provided method connect takes the root of the tree as its parameter and handles edge cases, like an empty tree, by immediately returning the root if it’s NULL. The use of helper function handleChild simplifies the logic for setting the next pointers during node processing. This function checks for the existence of a child (either left or right), and:

  • If previous is not NULL, it links previous->next to the current child.
  • If previous is NULL, it means this child is the first node at the current level, hence, it initializes first.
  • It updates previous to this child, preparing it to establish the next link.

The main loop iterates as long as there are nodes at the current level. Within each level, it navigates using current->next to access and link all children nodes by calling handleChild.

  • The result is a tree where each node either points to its immediate right sibling or NULL if it is the last node at its level.
  • This approach operates in linear time, O(n), where n is the number of nodes, since each node is visited exactly once.
  • It acts in-place, modifying the original tree without using extra space proportional to the number of tree levels or nodes.

This method is efficient, succinct, and addresses the problem directly by leveraging pointer manipulation to link nodes at the same depth in the binary tree recursively.

java
class Solution {
    Node previous, first;
    
    public void handleChild(Node child) {
        if (child != null) {
            if (this.previous != null) {
                this.previous.next = child;
            } else {
                this.first = child;
            }
            this.previous = child;
        }
    }
    
    public Node connect(Node root) {
        if (root == null) {
            return root;
        }
    
        this.first = root;
        Node current = first;
    
        while (this.first != null) {
            this.previous = null;
            current = this.first;
            this.first = null;
    
            while (current != null) {
                this.handleChild(current.left);
                this.handleChild(current.right);
                current = current.next;
            }
        }
    
        return root;
    }
}

The Java solution provided addresses the problem of connecting the next right pointers in each node of a binary tree where the tree may not necessarily be perfect. Here is how the implementation works:

  • Initialization of Helpers: Two node pointers, previous and first, are declared. previous is used to track the previous node in the next level, while first is used to track the first node of the next level.

  • Child Node Handling: The handleChild method handles the connection of child nodes. If a child node exists:

    • If a previous node is already set, establish a link from the previous node's next to the current child node.
    • If no previous node is set, update the first to point to this child since it represents the start of the new level.
    • Update previous to the current child, shifting it rightward as it progresses across levels.
  • Main Connection Logic: The connect method performs the level-by-level connection:

    1. Start by setting the root as the initial current node.
    2. Continue the process until there are nodes to visit in the next levels (first is not null):
      • Reset previous to null for each new level.
      • Traverse each node at the current level (current), handling its left and right children using the handleChild method to establish appropriate next connections.
      • Move to the next node horizontally using the next pointer.
  • Final Output: Once all connections are established, the modified root with updated pointers is returned.

This solution efficiently works through each level of the tree, using next pointers to manage traversal without requiring auxiliary data structures like queues, optimizing both time and space complexity. This approach ensures that each node points to its next right node, or null if no such node exists, thereby solving the problem of populating next right pointers effectively.

c
void linkChild(struct Node* child, struct Node** lastNode, struct Node** firstNode) {
    if (child) {
        if (*lastNode) {
            (*lastNode)->next = child;
        } else {
            *firstNode = child;
        }
        *lastNode = child;
    }
}
    
struct Node* connectNodes(struct Node* root) {
    if (!root) {
        return root;
    }
    struct Node* currentStart = root;
    while (currentStart) {
        struct Node* lastChild = NULL;
        struct Node* current = currentStart;
        currentStart = NULL;
        while (current) {
            linkChild(current->left, &lastChild, &currentStart);
            linkChild(current->right, &lastChild, &currentStart);
            current = current->next;
        }
    }
    return root;
}

The provided C code solves the problem of connecting the next right pointers for each node in a binary tree, particularly when the tree is not a perfect binary tree. Here's a breakdown of the solution approach:

  • Implement two main functions, linkChild and connectNodes.

  • linkChild assists in linking child nodes at each level. It takes a child node and pointers to track the last node at the current level (lastNode) and the first node at the next level (firstNode). If the child node exists:

    • If there's already a last node in the current level, set its next pointer to the current child node.
    • If no last node has been set at the current level, mark this child as the start of the level (firstNode).
    • Update lastNode to the current child node to establish the connection for subsequent nodes.
  • connectNodes uses linkChild to set up the next pointers for all nodes:

    • Start from the root; if it's null, simply return it.
    • Use a loop to manage each level of the tree, starting with the current level's root.
      • Initialize pointers for tracking purposes (lastChild for the last node of the current level and currentStart for the start node of the next level).
      • Traverse nodes at the current level using a while loop. For each node, attempt to link its left and right children using linkChild.
      • Move to the next node in the current level using the next right pointers already set in the previous levels.
    • Continue this process until all levels are linked.

In essence, this code successfully manipulates next pointers to create level-wise connections among nodes in the tree, using a level order traversal and handling nodes without the need for additional data structures like queues or arrays, which are commonly used in breadth-first traversal approaches. This method is particularly efficient for memory usage since it leverages the existing tree structure without additional overhead.

js
var connectNodes = function (rootNode) {
    if (!rootNode) {
        return rootNode;
    }
    let leftEdge = rootNode;
    let previous = null;
    let current = null;
    while (leftEdge) {
        previous = null;
        current = leftEdge;
        leftEdge = null;
        while (current) {
            let result = processNode(current.left, previous, leftEdge);
            previous = result[0];
            leftEdge = result[1];
            result = processNode(current.right, previous, leftEdge);
            previous = result[0];
            leftEdge = result[1];
            current = current.next;
        }
    }
    return rootNode;
};
    
var processNode = function (node, previous, leftEdge) {
    if (node) {
        if (previous) {
            previous.next = node;
        } else {
            leftEdge = node;
        }
        previous = node;
    }
    return [previous, leftEdge];
};

The provided JavaScript function connectNodes is designed to connect the next right pointers in each node of a binary tree where each node may not necessarily have both children. This function helps in setting up the next pointer for all the nodes on the same level to point to the next adjacent node on the right, facilitating a level-wise connection.

Here's a concise outline of how the code operates:

  1. Initially, it handles an edge case where the input rootNode might be null. If the root is null, it immediately returns the root.
  2. The leftEdge variable is used to keep track of the leftmost node of the next level. Starting from the root, the outer while loop iterates over the levels of the tree.
  3. Inside the outer loop, current initially points to the leftmost node of the current level. It iterates through the nodes at the current level using a while loop.
  4. The inner while loop processes each child of the current node (both left and right) by calling processNode. The processNode function determines if the child node should be the new leftEdge if it’s the first node on the next level, or connects it with the previous node in the level.
  5. After processing both children of current, the next of the current node makes it possible to move linearly to the next node on the same level without needing a recursive or additional data structure.
  6. The function continues until all levels are processed.

Each call to processNode potentially updates previous, which serves as the last visited node on the current level, ensuring that next pointers are set correctly. The return values from processNode include:

  • the updated previous node,
  • the potentially updated leftEdge if a new level has started.

The end result is that every node's next pointer will point to the next right node on the current level or to null if it is the rightmost node. This function enhances the navigational efficiency within a binary tree by allowing level-wise traversal using next pointers.

python
class Solution:
    
    def linkNode(self, node, previous, firstNode):
        if node:
            if previous:
                previous.next = node
            else:
                firstNode = node
            previous = node
        return previous, firstNode
    
    def connect(self, root: Optional["Node"]) -> Optional["Node"]:
        if not root:
            return root
    
        firstNode = root
    
        while firstNode:
            lastNode, currNode = None, firstNode
            firstNode = None
    
            while currNode:
                lastNode, firstNode = self.linkNode(currNode.left, lastNode, firstNode)
                lastNode, firstNode = self.linkNode(currNode.right, lastNode, firstNode)
                currNode = currNode.next
        return root

In this Python 3 solution, the goal is to populate each node's next pointer in a binary tree, which may not be perfect, where each node points to its nearest right neighbor on the same level. If no such neighbor exists, the next pointer should be set to None. This is executed iteratively using level-order traversal, commonly known as Breadth First Search (BFS).

Here's a breakdown of how the solution works:

  • A helper method linkNode is used to connect the current node to its next node if any, and reset pointers to the starting node of the next level when necessary.
  • In the connect method:
    1. Return immediately if the root is None. This checks for an empty input.
    2. Start with firstNode set to root, which keeps track of the first node of the current level.
    3. Use a loop to process nodes level by level until there are no nodes left to process.
    4. Within this loop, initialize lastNode as None to start linking nodes at each level, and currNode as the starting node of the current level. Reinitialize firstNode to None to determine the first node of the next level.
    5. As you traverse nodes of the current level using a second nested loop, use linkNode to process left and right children of currNode. This function handles the majority of the connection logic and updating of pointers.
    6. Shift focus to the next node on the current level using currNode = currNode.next.

Finally, after all levels are processed, the tree with updated next pointers is returned. This approach ensures all nodes' next pointers are appropriately set without using additional memory for a queue, making it efficient in terms of space. Each node is only processed once, leading to a time complexity of O(n), where n is the number of nodes in the tree.

Comments

No comments yet.