Given the root
of a binary tree, return the preorder traversal of its nodes' values. Write both a recursive and an iterative solution.
Example 1:
Input: root = [1,null,2,3]
Output: [1,2,3]
Explanation:
1
\
2
/
3
Example 2:
Input: root = [1,2,3,4,5,null,8,null,null,6,7,9]
Output: [1,2,4,5,6,7,3,8,9]
Explanation:
1
/ \
2 3
/ \ \
4 5 8
/ \ /
6 7 9
Example 3:
Input: root = []
Output: []
Example 4:
Input: root = [1]
Output: [1]
Constraints:
[0, 100]
.-100 <= Node.val <= 100
Can you provide both a recursive and an iterative solution? Discuss the time and space complexity of each solution. How would your solutions handle edge cases such as an empty tree or a tree with only one node?
Given the root of a binary tree, return the preorder traversal of its nodes' values.
The most straightforward way to perform a preorder traversal is by using recursion. The basic idea is to visit the root node first, then recursively traverse the left subtree, and finally recursively traverse the right subtree.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def preorder_recursive(root):
if root is None:
return []
result = [root.val]
result += preorder_recursive(root.left)
result += preorder_recursive(root.right)
return result
An iterative solution can be implemented using a stack. The algorithm pushes the root node onto the stack, then repeatedly pops a node, adds its value to the result, and pushes its right and left children onto the stack (right child first to ensure left child is processed first).
def preorder_iterative(root):
if root is None:
return []
result = []
stack = [root]
while stack:
node = stack.pop()
result.append(node.val)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return result
Both recursive and iterative solutions are provided above.