Flatten Binary Tree to Linked List medium
Problem Statement
Given the root
of a binary tree, flatten the tree into a "linked list" in-place.
The "linked list" should use the same TreeNode
nodes as the original tree and the right pointer of every node should point to the next node in the list and the left pointer of every node should be NULL.
Example 1
Input: root = [1,2,5,3,4,null,6] Output: [1,null,2,null,3,null,4,null,5,null,6]
Example 2
Input: root = [] Output: []
Steps
-
Recursive Approach: We will use a recursive post-order traversal to flatten the tree. The core idea is to process the left and right subtrees recursively, and then connect them to the current node.
-
Post-order Traversal: We flatten the right subtree first, then the left subtree, and finally connect them to the current node.
-
Connecting Nodes: After flattening the left and right subtrees, we need to connect the end of the flattened left subtree to the beginning of the flattened right subtree. This creates a continuous linked list structure.
-
Handle Null Nodes: We need to gracefully handle the cases where either the left or right subtree is null.
-
In-place Modification: The solution should modify the original tree directly without creating a new tree.
Explanation
The recursive function flatten
follows these steps:
-
Base Case: If the current node is
None
, it does nothing. -
Recursive Calls: It recursively flattens the left subtree and the right subtree.
-
Connecting Left Subtree: If the left subtree exists, it finds the tail of the flattened left subtree and makes it point to the original right subtree. It then updates the current node's right child to be the flattened left subtree.
-
Setting Left Child to None: It sets the left child of the current node to
None
to ensure we have a linked list structure.
The post-order traversal ensures that the subtrees are processed before the parent node, and the connections are made correctly to form the linked list.
Code
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: TreeNode) -> None:
"""
Do not return anything, modify root in-place instead.
"""
def flatten_recursive(node):
if not node:
return None, None # return None, None if node is None.
left_tail, left_end = flatten_recursive(node.left)
right_tail, right_end = flatten_recursive(node.right)
if left_tail:
left_end.right = node.right
node.right = node.left
node.left = None
current_tail = node
if right_end:
current_tail = right_tail
return node, current_tail
flatten_recursive(root)
Complexity
- Time Complexity: O(N), where N is the number of nodes in the tree. We visit each node exactly once during the recursive traversal.
- Space Complexity: O(H), where H is the height of the tree. This is due to the recursive call stack. In the worst case (a skewed tree), H can be equal to N, resulting in O(N) space complexity. However, for a balanced tree, H is log(N), resulting in O(log N) space complexity.