We're given a BST and need to rearrange its pointers so it becomes a sorted circular doubly linked list. No new nodes are created. We reuse the existing tree nodes and change what left and right point to: left becomes the prev pointer of the doubly linked list, and right becomes the next pointer.
Since it's a BST, an in-order traversal visits nodes in sorted order. The problem reduces to: visit the nodes in that order, link each one to the node visited before it, and finally connect the head and tail to make the list circular.
0 <= number of nodes <= 2000 → The tree can be empty, so every approach must return null for a null root before touching any pointers.-1000 <= Node.val <= 1000 → Values are never added or multiplied, only linked, so the range has no overflow implications.All values are unique → Each node has a distinct position in the sorted order, so no tie-breaking logic is needed.An in-order traversal of the BST visits nodes in sorted order. Collect them into a list, then rewire the pointers in a second pass: walk through the list, set each node's right to the next node and each node's left to the previous node, and connect the first and last nodes to make the list circular.
Separating "get the sorted order" from "link the nodes" keeps each step simple. No pointers change during the traversal itself, so the rewiring cannot interfere with how we walk the tree.
nodes[i].right = nodes[i+1] and nodes[i+1].left = nodes[i].head.left = tail and tail.right = head.Loading animation...
The list of collected nodes is the only reason this approach needs O(n) extra space. The next approach links nodes during the traversal itself and drops that list.
Instead of collecting all nodes and linking them afterward, we can link nodes together during the in-order traversal itself. During in-order traversal, the previously visited node is exactly the predecessor of the current node in sorted order, so a single pointer to the last processed node is all the state needed to wire up the doubly linked list.
Maintain two pointers: first (the head of the list, the smallest node) and last (the most recently processed node). As we visit each node during in-order traversal:
last.right = current (the previous node's next pointer)current.left = last (the current node's prev pointer)last = currentWhen the traversal is done, first holds the smallest node and last holds the largest. Connect them to close the circle: first.left = last and last.right = first.
Overwriting pointers in the middle of the traversal is safe because of the order in which they are touched. When the traversal processes a node, its left subtree is already fully visited, so reassigning current.left affects nothing the traversal still needs. Reassigning last.right is also safe: a node's right pointer is only overwritten after the traversal has already descended into its right subtree, and the recursive call inOrder(node.right) received the original child reference before the reassignment. The traversal keeps walking the original tree structure even as the list pointers are written over it.
first = null (will track the smallest node) and last = null (will track the most recently visited node).last is not null, link last.right = current and current.left = last.last is null, this is the first (smallest) node, so set first = current.last = current.first.left = last and last.right = first.first.Loading animation...
The recursive approach puts the O(h) space on the call stack, which has a fixed limit. The same traversal can run iteratively with an explicit stack on the heap.
The logic is identical to the recursive approach: traverse in order and link each node to the previously visited one. The difference is that we drive the traversal with our own stack instead of the call stack, using the standard iterative in-order pattern: push nodes while walking left, pop and process, then move to the right child.
The rewiring stays safe here for the same ordering reason as in the recursive version: after processing a node we read current.right to continue the traversal, and that pointer is not overwritten until the next node is popped, which happens after the read. A deeply skewed tree no longer risks overflowing the call stack, since the explicit stack grows on the heap.
first = null, last = null.node.left until we reach null.last (same logic as the recursive approach).node.right and repeat step 3.first.Loading animation...