Loading problems...
TL;DR: Recursively flatten the left and right subtrees, then graft the flattened left subtree between the root and the flattened right subtree.
The problem requires transforming a binary tree into a specific type of "linked list" in-place. While the structure uses the TreeNode class, the resulting topology must be a single chain of nodes following the pre-order traversal sequence (Root Left Right). In this flattened state, all left pointers must be null, and right pointers act as the next pointers of a linked list. This is a popular interview question that tests your ability to manipulate pointer references within a recursive structure, specifically targeting LeetCode 114.
The most straightforward way to solve this is to ignore the "in-place" preference initially and focus on the output requirement: a pre-order sequence.
current at index i, set current.left to null and current.right to the node at index i+1.textfunction flatten(root): list = [] preorder(root, list) for i from 0 to list.length - 2: list[i].left = null list[i].right = list[i+1] list[last].left = null list[last].right = null
The key to solving LeetCode 114 in-place lies in trusting the recursive function (the "leap of faith").
If we assume our flatten function works correctly, then calling flatten(root.left) will turn the left subtree into a straight line (linked list), and flatten(root.right) will turn the right subtree into a straight line.
Once the subtrees are flattened, the problem reduces to a simple pointer rewiring operation at the current root:
root.right (the flattened right subtree).root.left (the flattened left subtree) to become the new root.right.root.right chain.root.left is set to null to satisfy the constraints.This logic maintains the pre-order invariant: Root is processed, followed immediately by the entire Left subtree (now on the right), followed by the entire Right subtree.
Visual Description: Imagine the recursion tree at a specific node. The left child represents a processed chain. We essentially "insert" the entire left chain between the node and its right child. We then perform this same logic for every node in the tree, working from the bottom up (post-order logic) or top-down depending on implementation, though the structural result aligns with pre-order.

We will implement a recursive DFS function.
null, return immediately.left child.right child.left child:
right child in a temporary variable tempRight.left child to root.right.root.left to null.root.right (which was the old left subtree).tempRight to this tail.This approach modifies the tree structure in place without allocating new nodes.
Let's trace the algorithm on a simple tree: Root(1), Left(2), Right(5).
flatten(1).flatten(2).
flatten(2.left) returns.flatten(2.right) returns.2 -> null.flatten(5).
5 -> null.tempRight = Node 5.1.right = Node 2.1.left = null.1 -> 2. Node 5 is detached in tempRight.1.right. We traverse from 1 to 2. Tail is 2.tail.right (2.right) = tempRight (5).1 -> 2 -> 5.[1, 2, 5].The correctness is based on structural induction.
flatten(root.left) and flatten(root.right) correctly produce flattened lists corresponding to the pre-order traversal of the left and right subtrees, respectively.root.right points to the head of the flattened left subtree, and the tail of that subtree points to the head of the flattened right subtree. The sequence becomes: Root -> Left Subtree (Preorder) -> Right Subtree (Preorder). This matches the definition of a pre-order traversal for the entire tree.cpp/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: void flatten(TreeNode* root) { if (!root) return; // Recursively flatten the subtrees flatten(root->left); flatten(root->right); // If there is a left child, we need to insert it if (root->left) { // Store the original right subtree TreeNode* tempRight = root->right; // Move left subtree to right root->right = root->left; root->left = nullptr; // Important: ensure left is null // Find the end of the new right subtree (old left subtree) TreeNode* current = root; while (current->right) { current = current->right; } // Attach the original right subtree current->right = tempRight; } } };
java/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */ class Solution { public void flatten(TreeNode root) { if (root == null) return; // Recursively flatten left and right subtrees flatten(root.left); flatten(root.right); // Post-order processing: Rewire connections if (root.left != null) { // Save the current right child TreeNode tempRight = root.right; // Move the left child to the right root.right = root.left; root.left = null; // Don't forget to null out the left pointer // Traverse to the end of the new right chain TreeNode current = root; while (current.right != null) { current = current.right; } // Attach the saved right child to the end current.right = tempRight; } } }
python# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def flatten(self, root: Optional[TreeNode]) -> None: """ Do not return anything, modify root in-place instead. """ if not root: return # Recursively flatten the subtrees self.flatten(root.left) self.flatten(root.right) # If there is a left child, insert it between root and right if root.left: temp_right = root.right # Move left subtree to right root.right = root.left root.left = None # Find the tail of the new right subtree current = root while current.right: current = current.right # Attach the original right subtree current.right = temp_right
The Tree DFS pattern is fundamental. Understanding the recursive "leap of faith" logic used in LeetCode 114 is directly applicable to:
Why do I get a Time Limit Exceeded or Stack Overflow?
root.left = null after moving the left subtree to the right.root.left still points to the old node, recursive calls might revisit it or cycles might be introduced, confusing the traversal logic.Why is part of my tree missing?
root.right without saving it to a temporary variable first.root.right = root.left, the original reference to the right subtree is lost if not cached.Why is my output not in Preorder?
prev pointer but traversing Left -> Right (standard preorder) instead of Right -> Left (reverse preorder).prev pointer to track the last visited node, standard preorder overwrites the right pointer of the current node before you visit the right child.