🧠
Brute Force (Pure Recursion)
💡 Starting with recursion helps understand the natural definition of preorder traversal and builds intuition before optimizing or switching to iterative methods.
Intuition
Preorder traversal means visiting the root node first, then recursively traversing the left subtree, followed by the right subtree. Recursion naturally fits this definition by calling the function on subtrees.
Algorithm
- Visit the current node and record its value.
- Recursively traverse the left subtree in preorder.
- Recursively traverse the right subtree in preorder.
- Combine the results to form the preorder traversal list.
💡 The recursion stack implicitly keeps track of nodes to visit next, which can be tricky to visualize at first.
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 preorderTraversal(root: Optional[TreeNode]) -> List[int]:
if root is None:
return []
return [root.val] + preorderTraversal(root.left) + preorderTraversal(root.right)
# Example usage:
# Construct tree: 1
# \
# 2
# /
# 3
# root = TreeNode(1, None, TreeNode(2, TreeNode(3), None))
# print(preorderTraversal(root)) # Output: [1, 2, 3]
Line Notes
def preorderTraversal(root: Optional[TreeNode]) -> List[int]:Defines the function signature with type hints for clarity.
if root is None:Base case: if the current node is null, return an empty list to stop recursion.
return [root.val] + preorderTraversal(root.left) + preorderTraversal(root.right)Visit root first, then recursively traverse left and right subtrees, concatenating results.
class TreeNode:Defines the binary tree node structure used in the problem.
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) return result;
result.add(root.val);
result.addAll(preorderTraversal(root.left));
result.addAll(preorderTraversal(root.right));
return result;
}
// Example usage:
// public static void main(String[] args) {
// TreeNode root = new TreeNode(1);
// root.right = new TreeNode(2);
// root.right.left = new TreeNode(3);
// Solution sol = new Solution();
// System.out.println(sol.preorderTraversal(root)); // Output: [1, 2, 3]
// }
}
Line Notes
public List<Integer> preorderTraversal(TreeNode root) {Method signature returning a list of integers representing preorder traversal.
if (root == null) return result;Base case: return empty list if node is null to end recursion.
result.add(root.val);Visit the root node first and add its value to the result list.
result.addAll(preorderTraversal(root.left));Recursively traverse the left subtree and add all its values.
#include <iostream>
#include <vector>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
vector<int> preorderTraversal(TreeNode* root) {
if (!root) return {};
vector<int> res = {root->val};
vector<int> left = preorderTraversal(root->left);
vector<int> right = preorderTraversal(root->right);
res.insert(res.end(), left.begin(), left.end());
res.insert(res.end(), right.begin(), right.end());
return res;
}
// Example usage:
// int main() {
// TreeNode* root = new TreeNode(1);
// root->right = new TreeNode(2);
// root->right->left = new TreeNode(3);
// vector<int> result = preorderTraversal(root);
// for (int val : result) cout << val << ' ';
// cout << endl; // Output: 1 2 3
// return 0;
// }
Line Notes
vector<int> preorderTraversal(TreeNode* root) {Function returns a vector of integers representing preorder traversal.
if (!root) return {};Base case: return empty vector if node is null to stop recursion.
vector<int> res = {root->val};Start result vector with current node's value.
res.insert(res.end(), left.begin(), left.end());Append preorder traversal of left subtree to result.
function TreeNode(val, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
function preorderTraversal(root) {
if (root === null) return [];
return [root.val].concat(preorderTraversal(root.left), preorderTraversal(root.right));
}
// Example usage:
// const root = new TreeNode(1, null, new TreeNode(2, new TreeNode(3), null));
// console.log(preorderTraversal(root)); // Output: [1, 2, 3]
Line Notes
function preorderTraversal(root) {Defines the preorder traversal function.
if (root === null) return [];Base case: return empty array if node is null.
return [root.val].concat(preorderTraversal(root.left), preorderTraversal(root.right));Visit root, then recursively traverse left and right subtrees, concatenating results.
function TreeNode(val, left = null, right = null) {Defines the TreeNode constructor function.
Each node is visited exactly once, so time is O(n). The recursion stack can go as deep as the height of the tree, which in worst case is O(n).
💡 For a tree with 20 nodes, this means about 20 function calls and 20 visits, which is efficient for interview standards.
Interview Verdict: Accepted
This approach is accepted and often the first step in interviews to demonstrate understanding of tree traversal.