🧠
Brute Force (Preorder Traversal + Rebuild)
💡 This approach exists to build intuition by separating traversal from reconstruction, helping beginners understand the problem before optimizing.
Intuition
First, perform a preorder traversal to collect nodes in a list, then rebuild the tree into a linked list using that list.
Algorithm
- Traverse the tree in preorder and store nodes in a list.
- Iterate over the list and set each node's left pointer to null.
- Set each node's right pointer to the next node in the list.
- Ensure the last node's right pointer is null.
💡 Separating traversal and reconstruction clarifies the problem but uses extra space, which is a tradeoff to understand.
from typing import Optional, List
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def flatten(root: Optional[TreeNode]) -> None:
nodes: List[TreeNode] = []
def preorder(node: Optional[TreeNode]):
if not node:
return
nodes.append(node)
preorder(node.left)
preorder(node.right)
preorder(root)
for i in range(len(nodes) - 1):
nodes[i].left = None
nodes[i].right = nodes[i + 1]
if nodes:
nodes[-1].left = None
nodes[-1].right = None
# Driver code to test
if __name__ == '__main__':
# Build tree: 1
# / \
# 2 5
# / \ \
# 3 4 6
root = TreeNode(1,
TreeNode(2, TreeNode(3), TreeNode(4)),
TreeNode(5, None, TreeNode(6)))
flatten(root)
# Print flattened list
curr = root
while curr:
print(curr.val, end=' -> ' if curr.right else '')
curr = curr.right
print()
Line Notes
nodes: List[TreeNode] = []Initialize list to store nodes in preorder
def preorder(node: Optional[TreeNode]):Define helper function for preorder traversal
nodes.append(node)Add current node to list to preserve traversal order
for i in range(len(nodes) - 1):Iterate to rewire nodes into linked list form
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class FlattenBinaryTree {
public void flatten(TreeNode root) {
List<TreeNode> nodes = new ArrayList<>();
preorder(root, nodes);
for (int i = 0; i < nodes.size() - 1; i++) {
nodes.get(i).left = null;
nodes.get(i).right = nodes.get(i + 1);
}
if (!nodes.isEmpty()) {
TreeNode last = nodes.get(nodes.size() - 1);
last.left = null;
last.right = null;
}
}
private void preorder(TreeNode node, List<TreeNode> nodes) {
if (node == null) return;
nodes.add(node);
preorder(node.left, nodes);
preorder(node.right, nodes);
}
// Driver code
public static void main(String[] args) {
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);
new FlattenBinaryTree().flatten(root);
TreeNode curr = root;
while (curr != null) {
System.out.print(curr.val);
if (curr.right != null) System.out.print(" -> ");
curr = curr.right;
}
System.out.println();
}
}
Line Notes
List<TreeNode> nodes = new ArrayList<>();Create list to hold nodes in preorder
preorder(root, nodes);Collect nodes in preorder traversal
nodes.get(i).left = null;Set left pointer to null to flatten
nodes.get(i).right = nodes.get(i + 1);Link current node to next node in list
#include <iostream>
#include <vector>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class Solution {
public:
void flatten(TreeNode* root) {
vector<TreeNode*> nodes;
preorder(root, nodes);
for (size_t i = 0; i + 1 < nodes.size(); ++i) {
nodes[i]->left = nullptr;
nodes[i]->right = nodes[i + 1];
}
if (!nodes.empty()) {
nodes.back()->left = nullptr;
nodes.back()->right = nullptr;
}
}
private:
void preorder(TreeNode* node, vector<TreeNode*>& nodes) {
if (!node) return;
nodes.push_back(node);
preorder(node->left, nodes);
preorder(node->right, nodes);
}
};
// Driver code
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 sol;
sol.flatten(root);
TreeNode* curr = root;
while (curr) {
cout << curr->val;
if (curr->right) cout << " -> ";
curr = curr->right;
}
cout << endl;
return 0;
}
Line Notes
vector<TreeNode*> nodes;Store nodes in preorder traversal order
void preorder(TreeNode* node, vector<TreeNode*>& nodes)Helper function to collect nodes recursively
nodes[i]->left = nullptr;Remove left child to flatten tree
nodes[i]->right = nodes[i + 1];Link current node to next node in preorder
class TreeNode {
constructor(val, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function flatten(root) {
const nodes = [];
function preorder(node) {
if (!node) return;
nodes.push(node);
preorder(node.left);
preorder(node.right);
}
preorder(root);
for (let i = 0; i < nodes.length - 1; i++) {
nodes[i].left = null;
nodes[i].right = nodes[i + 1];
}
if (nodes.length > 0) {
nodes[nodes.length - 1].left = null;
nodes[nodes.length - 1].right = null;
}
}
// Driver code
const root = new TreeNode(1,
new TreeNode(2, new TreeNode(3), new TreeNode(4)),
new TreeNode(5, null, new TreeNode(6))
);
flatten(root);
let curr = root;
const result = [];
while (curr) {
result.push(curr.val);
curr = curr.right;
}
console.log(result.join(' -> '));
Line Notes
const nodes = [];Array to hold nodes in preorder
function preorder(node)Recursive helper to traverse tree preorder
nodes.push(node);Add current node to traversal list
nodes[i].left = null;Set left pointer to null to flatten
We visit each node once during preorder traversal and store all nodes in a list, then iterate once more to rewire pointers.
💡 For n=20 nodes, this means about 40 operations for traversal and rewiring, which is manageable but uses extra memory.
Interview Verdict: Accepted but uses extra space
This approach works but is not optimal because it uses extra space; it is useful to understand the problem before optimizing.