Back to DSA & Algorithms
DSA & Algorithms
easy
mid

How would you populate next right pointers in each node of a binary tree?

For each node in a binary tree, point its `next` to the node immediately to its right at the same level (or null if last). Two approaches: BFS using a queue (O(n) time, O(n) space); level-by-level traversal using the `next` pointers built in previous levels for O(1) extra space (the canonical perfect-tree solution).

4 min read·~25 min to think through

LeetCode classic. Given a binary tree (often described as "perfect" — all leaves at the same level), wire each node's next to its right neighbor at the same level.

ts
     1                1null
   /   \            / \
  2     3          23null
 / \   / \        / \ / \
4   5 6   7       4567null

Approach 1 — BFS with queue

Level-order traversal; within each level, link adjacent nodes:

js
function connect(root) {
  if (!root) return null;
  const queue = [root];
  while (queue.length) {
    const size = queue.length;
    let prev = null;
    for (let i = 0; i < size; i++) {
      const node = queue.shift();
      if (prev) prev.next = node;
      prev = node;
      if (node.left) queue.push(node.left);
      if (node.right) queue.push(node.right);
    }
    // prev.next implicitly null
  }
  return root;
}

Time O(n), Space O(n) (queue width up to n/2 at the bottom level).

Approach 2 — Use built next pointers (O(1) extra space)

The canonical answer for perfect binary trees: walk level by level, using the next pointers built on the level above to traverse without a queue.

js
function connect(root) {
  if (!root) return null;
  let leftmost = root;

  while (leftmost.left) {                    // perfect tree: while not at leaves
    let head = leftmost;
    while (head) {
      head.left.next = head.right;           // (1) link within parent
      if (head.next) {                       // (2) link across parents
        head.right.next = head.next.left;
      }
      head = head.next;
    }
    leftmost = leftmost.left;                // next level
  }
  return root;
}

Time O(n), Space O(1) (besides input).

Why this works

For each parent on the current level:

  1. Link parent.left.next = parent.right — connect siblings.
  2. Link parent.right.next = parent.next.left — connect across parent boundaries (using the next we built one level up).

After processing the level, drop to leftmost.left to start the next level.

Variant — non-perfect tree (LeetCode 117)

If the tree isn't perfect (missing children), the children-linking step is messier — you need to find the first available child of parent.next's descendants. The pattern:

js
function connect(root) {
  let head = root;
  while (head) {
    let dummy = new Node();        // dummy head of next level
    let tail = dummy;
    for (let node = head; node; node = node.next) {
      if (node.left)  { tail.next = node.left;  tail = tail.next; }
      if (node.right) { tail.next = node.right; tail = tail.next; }
    }
    head = dummy.next;
  }
  return root;
}

Use a dummy head to build the next level's linked list as you walk the current level. Clean and handles any tree shape.

Edge cases

  • Empty tree.
  • Single node — no next links to set; returns root.
  • Lopsided tree (variant 117).

Interview framing

"Two clean approaches. BFS with a queue: level-order traversal, linking nodes in each level — O(n) time, O(n) space. The O(1)-space approach uses the next pointers built on the level above to traverse the next level without a queue: for each parent on the current level, link parent.left.next = parent.right and parent.right.next = parent.next?.left; then drop to leftmost.left for the next level. Works directly on a perfect tree. For a general (non-perfect) tree, walk the current level building the next level's linked list with a dummy-head — same O(1) extra space."

Follow-up questions

  • Why does the O(1)-space approach require the previous level's next pointers?
  • How does the dummy-head variant handle missing children?
  • What's the queue's max size in the BFS approach?
  • Walk through with a small example.

Common mistakes

  • Forgetting the across-parent link (head.right.next = head.next.left).
  • Off-by-one on level transitions.
  • BFS approach using array.shift() with O(n) cost per call.
  • Treating non-perfect trees with the perfect-tree algorithm.

Performance considerations

  • O(n) time always. BFS uses O(n) queue space; the next-pointer approach uses O(1). Avoid array.shift() in BFS — use an index or linked-list queue.

Edge cases

  • Empty tree.
  • Single node.
  • Non-perfect tree — use dummy-head variant.
  • Right child without left child (variant 117).

Real-world examples

  • Tree-shaped data (org charts, comment threads) where you want left-to-right traversal per level.

Senior engineer discussion

Seniors prefer the O(1)-space variant, recognize the dummy-head trick for the non-perfect case, and articulate the level-by-level reuse of just-built next pointers as the key insight.

Related questions