Given the root of a binary tree, modify the tree in-place so that it becomes a linked-list-like structure following the tree's preorder traversal.
After flattening:
Every node's
leftpointer must benull.Every node's
rightpointer must point to the next node in preorder.The original
TreeNodestructure must be reused.
Return the root of the flattened tree.
Example 1
Input:root = [1, 2, 5, 3, 4, null, 6]
Output:[1, null, 2, null, 3, null, 4, null, 5, null, 6]
Explanation:
The preorder traversal of the original tree is 1 -> 2 -> 3 -> 4 -> 5 -> 6. After flattening, every left pointer becomes null, while the right pointers connect the nodes in this preorder sequence.
Example 2
Input:root = [1, 2, 3]
Output:[1, null, 2, null, 3]
Explanation:
The preorder traversal is 1 -> 2 -> 3, so the flattened tree contains the same sequence connected only through right pointers.
Approach 1
The flattened tree must follow exactly the same order as a preorder traversal:
Root → Left → Right
A straightforward approach is to first perform preorder traversal and store references to all visited nodes in a list. Once traversal is completed, the required ordering is already available.
The stored nodes can then be reconnected so that every node points to the next node through its right pointer, while its left pointer is cleared.
This keeps traversal and pointer modification separate, which makes the approach simple to understand, but storing all nodes requires additional linear space.
Algorithm
A preorder traversal is performed, and every visited node is stored in a list because preorder gives exactly the order required in the flattened tree.
After traversal has been completed, consecutive nodes in the stored list are processed.
For each node except the last one, its
leftpointer is set tonullbecause the flattened structure must not contain left links.Its
rightpointer is connected to the next node in the preorder list so that the required sequence is preserved.For the final node, both child pointers are adjusted so that it becomes the end of the flattened structure.
After all links have been rearranged, the original root is returned.
Dry Run
Flatten Binary Tree Appraoch 1 Dry Run .png
Solution
#include <bits/stdc++.h>using namespace std;struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int value) { val = value; left = nullptr; right = nullptr; }};class Solution {private: // Stores nodes in the exact preorder // required by the flattened tree. void preorder( TreeNode* root, vector<TreeNode*>& nodes ) { if (root == nullptr) { return; } nodes.push_back(root); preorder(root->left, nodes); preorder(root->right, nodes); }public: // Reconnects preorder nodes into // one right-linked chain. TreeNode* flatten(TreeNode* root) { if (root == nullptr) { return nullptr; } vector<TreeNode*> nodes; preorder(root, nodes); // Consecutive preorder nodes are linked // through right pointers only. for (int i = 0; i < nodes.size() - 1; i++) { nodes[i]->left = nullptr; nodes[i]->right = nodes[i + 1]; } // The final node terminates // the flattened structure. nodes.back()->left = nullptr; nodes.back()->right = nullptr; return root; }};int main() { TreeNode* root = new TreeNode(1); root->left = new TreeNode(2); root->right = new TreeNode(5); root->left->left = new TreeNode(3); root->left->right = new TreeNode(4); root->right->right = new TreeNode(6); Solution solution; root = solution.flatten(root); while (root != nullptr) { cout << root->val << " "; root = root->right; } return 0;}Complexity Analysis
Let N be the number of nodes in the binary tree and H be the height of the tree.
Time Complexity: O(N), where N is the number of nodes in the binary tree. Every node is visited once during preorder traversal and processed once more while the stored nodes are reconnected.
Space Complexity: O(N), where N is the number of nodes stored in the preorder list. The recursive traversal may additionally require up to O(H) stack space, where H is the height of the binary tree.
Approach 2
Storing the complete preorder traversal can be avoided by creating the required links while recursion returns.
The desired flattened order is:
Root → Left → Right
If the tree is processed in the reverse order:
Right → Left → Root
a pointer named previous can be maintained. The name represents the node that should appear immediately after the current node in the final flattened preorder sequence.
Once both subtrees have been processed, the current node can be connected directly to previous.
The following updates are performed:
current.right = previous
current.left = null
previous = current
In this way, the flattened structure is built backward while only the recursion stack is required.
Algorithm
A pointer named
previousis maintained to represent the node that should immediately follow the current node in the final flattened preorder sequence.The right subtree is processed before the left subtree because the flattened list is being constructed in reverse preorder order.
After both recursive calls have been completed, the current node's
rightpointer is connected toprevious.The current node's
leftpointer is set tonullbecause no left links are allowed in the flattened structure.previousis updated to the current node so that the next ancestor processed during recursion can be connected to it.Once the root has been processed, the complete preorder-linked structure has been formed.
Dry Run
Flatten Binary Tree Appraoch 2 Dry Run .png
Solution
#include <bits/stdc++.h>using namespace std;struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int value) { val = value; left = nullptr; right = nullptr; }};class Solution {private: TreeNode* previous; // Processes nodes in reverse preorder so // previous is always the next flattened node. void reversePreorder(TreeNode* root) { if (root == nullptr) { return; } reversePreorder(root->right); reversePreorder(root->left); // previous is the node that must follow // the current node in normal preorder. root->right = previous; root->left = nullptr; previous = root; }public: // Flattens the tree using reverse // preorder and recursion. TreeNode* flatten(TreeNode* root) { previous = nullptr; reversePreorder(root); return root; }};int main() { TreeNode* root = new TreeNode(1); root->left = new TreeNode(2); root->right = new TreeNode(5); root->left->left = new TreeNode(3); root->left->right = new TreeNode(4); root->right->right = new TreeNode(6); Solution solution; root = solution.flatten(root); while (root != nullptr) { cout << root->val << " "; root = root->right; } return 0;}Complexity Analysis
Let N be the number of nodes in the binary tree and H be the height of the tree.
Time Complexity: O(N), where N is the number of nodes in the binary tree. Every node is processed exactly once.
Space Complexity: O(H), where H is the height of the binary tree, due to the recursion stack. This becomes O(N) for a skewed tree and O(log N) for a balanced tree.
Approach 3
The tree can also be flattened without storing nodes and without using recursion.
A pointer named current is used to represent the node whose links are currently being rearranged.
Whenever current has a left subtree, preorder traversal requires the entire left subtree to appear before the original right subtree:
current → left subtree → right subtree
Therefore, the left subtree must be moved to current.right.
Before this can be done, the original right subtree must be preserved. A pointer can be moved to the rightmost node of the left subtree. This node is important because after the left subtree has been rewired into the right chain, it becomes the final node visited before preorder should continue into the original right subtree.
The original right subtree is therefore attached to this rightmost node. The left subtree is then shifted to the right, and current.left is cleared.
The process continues by moving current through the newly formed right pointers.
Algorithm
A pointer named
currentis initialized with the root so that the tree can be processed directly through its existing links.While
currentis notnull, its local subtree structure is examined.If no left child exists, no rewiring is required at that node, and
currentis advanced to its right child.If a left subtree exists, its rightmost node is located because that node must connect to the original right subtree after the left subtree is moved.
The original
current.rightsubtree is attached to therightpointer of this rightmost node so that it is not lost.The left subtree is moved to
current.right, andcurrent.leftis set tonull, placing the former left subtree immediately after the current node in preorder.currentis then advanced through its right pointer, and the process is continued until every node has been rewired.
Dry Run
Flatten Binary Tree Appraoch 3 Dry Run .png
Solution
#include <bits/stdc++.h>using namespace std;struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int value) { val = value; left = nullptr; right = nullptr; }};class Solution {public: // Rewires the tree directly into preorder // using constant auxiliary space. TreeNode* flatten(TreeNode* root) { TreeNode* current = root; while (current != nullptr) { if (current->left != nullptr) { TreeNode* rightmost = current->left; // The rightmost node of the left subtree // must precede the original right subtree. while (rightmost->right != nullptr) { rightmost = rightmost->right; } // The original right subtree is preserved // after the complete left subtree. rightmost->right = current->right; // The left subtree is moved to the right // because preorder visits it next. current->right = current->left; current->left = nullptr; } current = current->right; } return root; }};int main() { TreeNode* root = new TreeNode(1); root->left = new TreeNode(2); root->right = new TreeNode(5); root->left->left = new TreeNode(3); root->left->right = new TreeNode(4); root->right->right = new TreeNode(6); Solution solution; root = solution.flatten(root); while (root != nullptr) { cout << root->val << " "; root = root->right; } return 0;}Complexity Analysis
Let N be the number of nodes in the binary tree.
Time Complexity: O(N), where N is the number of nodes in the binary tree. Although rightmost nodes of left subtrees are searched during rewiring, the traversal and pointer rearrangements together remain linear over the complete tree.
Space Complexity: O(1), because the tree is modified in-place using only a constant number of pointers such as current and the rightmost-node pointer.
Interview follow-up Questions
The nodes appear in the tree's preorder traversal order: root first, followed by the left subtree and then the right subtree.
Be the first to add a comment.