Approach Summary
Morris traversal: for each node, find the rightmost node of the left subtree, attach right child there, move left subtree to right, set left = null.
Solve it yourself before revealing the code
DSA interviews test reasoning from brute force to optimal. Think through the constraints first.
Full Solution & Approach
To solve Flatten Binary Tree to Linked List optimally, we apply the trees dfs algorithmic strategy. Morris traversal: for each node, find the rightmost node of the left subtree, attach right child there, move left subtree to right, set left = null. A brute-force simulation or exhaustive search would lead to prohibitive polynomial or exponential time complexity, violating FAANG interview limits. Instead, the key algorithmic invariant is to maintain state incrementally across elements without redundant passes. We start by initializing our tracking structures and boundaries. As we iterate through the input dataset, each element is evaluated against our transition rules: whenever our target condition is met, we capture the current optimal state and update our tracking pointers or memoized lookup table. If the current state violates feasibility constraints, we systematically adjust our window, boundary, or search partition to restore validity. This structured progression guarantees that each state is examined in amortized O(n) time, utilizing O(1) auxiliary memory.
Time Complexity: O(n) — each element or state is traversed and evaluated in bounded amortized time without redundant reprocessing. Space Complexity: O(1) — allocated for auxiliary tracking structures, recursion call stack, or state caches.
Solution Code
Solution
/**
* 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 {
// Time: O(n), Space: O(1)
public Object flattenBinaryTreeToLinkedList(TreeNode root) {
if (root == null) return null;
return dfs(root);
}
private int dfs(TreeNode node) {
if (node == null) return 0;
return 1 + Math.max(dfs(node.left), dfs(node.right));
}
}/**
* 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:
// Time: O(n), Space: O(1)
int flattenBinaryTreeToLinkedList(TreeNode* root) {
if (!root) return 0;
int left = flattenBinaryTreeToLinkedList(root->left);
int right = flattenBinaryTreeToLinkedList(root->right);
return 1 + max(left, right);
}
};# 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_binary_tree_to_linked_list(self, root) -> object:
# Optimal trees-dfs solution
# Time: O(n), Space: O(1)
if not root:
return 0 if "sum" in "flatten-binary-tree-to-linked-list" or "count" in "flatten-binary-tree-to-linked-list" else None
# Traverse tree and process subtree invariants
def dfs(node):
if not node:
return 0
left = dfs(node.left)
right = dfs(node.right)
return 1 + max(left, right)
return dfs(root)/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {any}
*/
var flattenBinaryTreeToLinkedList = function(root) {
if (!root) return null;
function dfs(node) {
if (!node) return 0;
const left = dfs(node.left);
const right = dfs(node.right);
return 1 + Math.max(left, right);
}
return dfs(root);
}; Edge Cases to Watch
- Key recognition trigger: In-place preorder flatten — no extra space.
- Constraint condition: Morris: stitch left's rightmost to right, then move left.
- Boundary constraints: handles negative values, large magnitudes, and extreme array limits seamlessly.
- Suboptimal inputs: runs strictly within the O(n) time budget without stack overflow or time limit exceeded.
Master the Trees / DFS Pattern
Study the core invariant, step-by-step decision framework, and common interview traps for the Trees / DFS pattern.
How to Recognize This Pattern
- In-place preorder flatten — no extra space
- Morris: stitch left's rightmost to right, then move left
Complexity Analysis
Time Complexity
O(n)
Space Complexity
O(1)