Algorithm

Populating Next Right Pointers in Each Node

Trees Pattern

Populating Next Right Pointers in Each Node

You are given a perfect binary tree — every internal node has exactly two children and all leaves are at the same depth. Each node carries an extra pointer, next, initially null. Set every node's next to the node immediately to its right on the same level, and to null for the rightmost node of each level. The tree is modified in place and the same root is returned. An empty tree is returned unchanged.

CONSTRAINTS
  • The number of nodes is in the range [0, 6000]
  • -100 <= Node.val <= 100
  • The tree is perfect: every internal node has two children, all leaves share one depth
  • The recursion stack does not count against extra space in the follow-up
EXAMPLE 1
Input: root = [1,2,3,4,5,6,7]
Output: [1,#,2,3,#,4,5,6,7,#] — # marks the end of a level
Each level becomes a chain read left to right: 2 → 3, and 4 → 5 → 6 → 7. Note that 5 → 6 crosses between different parents.
EXAMPLE 2
Input: root = [1,2,3]
Output: [1,#,2,3,#]
2 points to 3 because they share a parent, and 3's next is null since nothing lies to its right.
EXAMPLE 3
Input: root = [1]
Output: [1,#]
A single node has no right neighbour, so its next stays null.
EXAMPLE 4
Input: root = []
Output: []
Nothing to link. Returning null unchanged is correct rather than an error.
Is the tree guaranteed to be perfect?
Yes for this version, and the O(1)-space method leans on it heavily. The follow-up problem drops the guarantee, and then finding the next node on a level requires scanning past possible gaps.
What should the rightmost node of a level point to?
Null. It stays as initialised, so the algorithm simply never assigns it.
Can I use a queue?
Yes, and it is a perfectly good first answer — walk level by level and link each node to the one dequeued after it. The interesting follow-up asks for O(1) extra space.
Do I need to link nodes across different parents?
Yes, and that is the hard half. Siblings are easy; the link from one parent's right child to the next parent's left child is the part that needs an idea.

The goal is to turn each level of the tree into a left-to-right chain. The level-by-level walk from Binary Tree Level Order Traversal already produces nodes in exactly that order, so a first solution writes itself: process a level, and point each node's next at whichever node the queue hands over after it, leaving the last one null.

python
while queue:
    n = len(queue)
    for i in range(n):
        node = queue.popleft()
        if i < n - 1:
            node.next = queue[0]        # the next node in this level, still queued
        if node.left:  queue.append(node.left)
        if node.right: queue.append(node.right)

That is correct and runs in O(N) time. Its cost is the queue, which on this tree holds an entire level — up to about N/2 nodes. The real question is whether we can do it with no extra structure at all.

The links you just built are a way to move sideways

Here is the observation that removes the queue. Once a level has been fully stitched, that level is a linked list. You can stand on its leftmost node and walk rightwards along next pointers, reaching every node of the level in order — without a queue, because the level is now storing its own ordering.

So the algorithm becomes: use the finished level above to walk across, and while walking, stitch the level below. Each level pays for the next one.

Standing on a node curr of the finished level, there are exactly two kinds of link to create beneath it:

- Between its own two children. curr.left.next = curr.right. Easy — we hold both.
- From its right child to the next parent's left child. These two nodes are neighbours on the level below but have different parents, so no direct link exists between them. But curr.next already points at that next parent, so the route is curr.right.next = curr.next.left. We hop sideways on our own level, then reach down.

The second link is the whole trick, and it is only available because the level we are standing on was stitched during the previous round. The root's level needs no stitching (one node, nothing to its right), which starts the induction off.

python
leftmost = root
while leftmost and leftmost.left:          # stop when the current level has no children
    curr = leftmost
    while curr:                            # walk across the finished level
        curr.left.next = curr.right        # siblings
        if curr.next:
            curr.right.next = curr.next.left   # across to the neighbouring parent
        curr = curr.next                   # step sideways using the existing link
    leftmost = leftmost.left               # drop to the start of the level just stitched
Crucial Notethis code dereferences curr.left and curr.right without checking them, which is safe only because the tree is perfect — an internal node always has both children, so if leftmost.left exists then every node on that level has two children. Remove that guarantee and the code crashes or, worse, silently skips links, because the next node on the level below may be several parents away with gaps in between. The follow-up problem handles exactly that, usually with a dummy head node to build each level's chain as it goes. Notice how much a single structural promise buys: it is what turns a scan-for-the-next-available-node into a direct curr.next.left.
Worked example:root 1, children 2 and 3; 2 has 4 and 5; 3 has 6 and 7
- leftmost = 1. Its level is trivially finished. Walk: at 1, link 2 → 3 (siblings). 1.next is null, so there is no crossing link. Level 1 is now the chain 2 → 3. Drop to leftmost = 2.
- leftmost = 2. Walk across the chain 2 → 3.
- At 2: link 4 → 5 (siblings). 2.next is 3, so link 5 → 3.left, which is 6 — the crossing link. Chain so far: 4 → 5 → 6.
- Step sideways via 2.next to 3. At 3: link 6 → 7 (siblings). 3.next is null, so no crossing link.
- Level 2 is now 4 → 5 → 6 → 7. Drop to leftmost = 4.
- leftmost = 4, but 4.left is null, so the loop ends. Every level is stitched.

The step from 2 to 3 is the one to watch: it moved horizontally along a pointer created in the previous round. Without that, reaching node 3 from node 2 would have required going back up to the root.

Cost, and the pattern

Each node is visited once as curr and does constant work, so O(N) time — the same as the queue version. The extra space is two pointers, O(1), down from O(W). Nothing was recomputed; we simply noticed that the output being built was itself a usable structure.

That is the idea worth extracting: when an algorithm's output is a set of links, check whether the links already written can be used to navigate while writing the rest. It is the same instinct as Morris Traversal, which borrowed the tree's null pointers to remember the way back, and it appears whenever a "build it in place" follow-up shows up. The general question to ask when an interviewer says "now do it in O(1) space" is: what am I storing in that auxiliary structure, and is that information already present, or already being written, somewhere in the data?

Interactive Strategy Visualization

Populating Next Right Pointers

Connecting Siblings at Each Level

1234567
Next Pointers
Starting BFS traversal...

Key Mechanics

  • Level-by-Level: Process nodes in each level from left to right using BFS.
  • Queue Peek: Each node's next pointer points to the front of the queue (next sibling).
  • Last Node: The rightmost node in each level points to NULL.
PROGRESSSTEP 0/4
Initialize BFS with root node.
USE CASE

Real-World Applications

This pattern is essential for level-order linked lists, serialization of perfect binary trees, and multi-threaded tree traversals where each thread processes one level. It's also used in game development for connecting entities at the same depth in scene graphs.

Strategy

Focus on the recursive nature of trees: solve for subtrees and combine results at the root.

"Divide and Conquer: Subproblem → Recurrence → Result"

O(N) Time · O(W) Space Queue Level Walk
O(N) Time · O(1) Space Stitch Using Previous Level's Links