Hi👋SpeedAlgo • Deliberate Practice & Cognitive Ergonomics for Software Engineers

An interactive algorithm mastery and technical interview preparation platform published by Hi👋WebEnterprise. Built for senior and staff software engineers preparing for rigorous coding screens at top tech companies (FAANG/MAMAA).

13 Core Algorithmic Patterns & 225 Practice Problems

  • 1. Two Pointers (16 Paradigms, 43 Problems): Opposite ends, sorted pair sums, palindrome verification, trapping rain water, 3Sum, container with most water — includes the Sliding Window and Fast & Slow Pointers paradigms (contiguous subarray invariants, longest substrings, Floyd's cycle detection, linked list middle).
  • 2. Binary Search (9 Paradigms, 14 Problems): Monotonic predicate partitioning (feasible(x)), boundary search, rotated sorted arrays, square roots, minimum ship capacity, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 11 Problems): Counting set bits, XOR cancellation, bit reversal, bitmask pairing, maximum XOR with a bitwise trie.
  • 4. Math & Geometry (8 Paradigms, 14 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (15 Paradigms, 24 Problems): Path sums, lowest common ancestor, tree diameter, validating BSTs, tree DP (House Robber III, Binary Tree Cameras).
  • 6. Tree/Graph Breadth-First Search (5 Paradigms, 12 Problems): Level-order traversals, shortest path in unweighted graphs, zig-zag traversals, rotting oranges, word ladders.
  • 7. Graphs (12 Paradigms, 22 Problems): Topological sort, cycle detection, Dijkstra's algorithm, bipartite graph validation, network delay.
  • 8. Backtracking (6 Paradigms, 14 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens, Sudoku solver.
  • 9. Dynamic Programming (13 Paradigms, 28 Problems): Memoization vs tabulation, 0/1 knapsack, unbounded knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (9 Paradigms, 11 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (7 Paradigms, 17 Problems): Trie (prefix tree), Union-Find (Disjoint Set Union), LRU Cache, LFU Cache, range-sum queries with updates.
  • 12. Stack (5 Paradigms, 9 Problems): Next greater element, largest rectangle in histogram, remove k digits, decode string, min stack.
  • 13. Intervals & Greedy (2 Paradigms, 6 Problems): Merge intervals, interval scheduling, meeting rooms by sweep line, jump game.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Read the pattern's mental model, loop invariant and Big-O proof, compare the pattern's template with the problem's solution side by side, and use the step-by-step debugger. The solution can also be shown in C#, Java, TypeScript, C++, Go or Rust for almost every problem.
  2. Stage 2 (Active Recall): Rebuild the solution from memory in a code editor, with an invariant checklist and optional progressive hints, and check it against a judged test suite.
  3. Stage 3 (AI Interview Coach, coming soon): A mock-interview stage still in development; for now, students go straight from Stage 2 to Stage 4.
  4. Stage 4 (Solve on Your Own): Solve a new problem on your own against a 15-minute timer; your code is graded against a test suite. Python and TypeScript run in your browser and C# runs on our server (design problems grade in Python and TypeScript).

Equipped with a spaced-repetition review hub on a fixed 7-step schedule (1 day up to 90 days), a two-pane Studio workspace, and study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Coins: New accounts get 40 free coins once, the daily claim adds +20 coins once a day, and inviting a friend earns you +25 coins when they complete their first practice step. These are the only ways to earn coins.
  • AI Coach: Each AI coach question costs 1-5 coins, priced by the server according to its size.
  • BYOK (Bring Your Own Key): AI coaching is free with your own Google Gemini, OpenAI or OpenRouter API key (BYOK).
  • Extras: Coins also unlock extras for 24 hours: a Recall hint level (1 coin), a Solve solution reveal (2), a LeetCode problem card's solutions (1) and a pattern's extra canonical problems (1).
  • Payments & Refunds: Nothing on the site is sold for money: coins can only be earned, never bought. There are no subscriptions or charges, so there is nothing to refund.
  • Platform Operator: Hi👋WebEnterprise. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

Arena
238Items
Theory Context•Depth-First Search (DFS)
EasyLC 104

Maximum Depth of Binary Tree (LeetCode 104)

Target Frequency:MetaAmazonApple

You're handed the root of a binary tree and asked how tall it is: its maximum depth.

The maximum depth counts the nodes on the single longest chain running from the root all the way down to whichever leaf sits farthest away.

Worked Examples

Example 1
Input:root = [3,9,20,null,null,15,7]
Output:3
9315207
Explanation: The longest path is 3 -> 20 -> 15 (or 7), which has 3 nodes.
Example 2
Input:root = [1,null,2]
Output:2
12
Explanation: The longest path is 1 -> 2, which has 2 nodes.

⚖️Formal Constraints & Bounds

  • The number of nodes in the tree is in the range [0, 104].

  • -100 <= Node.val <= 100

Deep-Dive & Conceptual Insights

Core Insight

Tree problems naturally decompose into identical subproblems on the left and right subtrees.

Real-World Scenario & Production Applications

Directory tree depth calculation in filesystems, DOM tree depth traversal in browser rendering engines.

Step-by-Step Execution Trace Table

StepCall FrameDepthActionChild Subtree ReturnsCombine Step (max(L, R) + 1)Value Returned Upward
1Node 3d=1⬇️ ENTERSuspends; waits for children——
2Node 9d=2⬇️ ENTERDescends into left child——
39.leftd=3⬇️↑ BASEnode is NoneBase case: empty contributes 00
49.rightd=3⬇️↑ BASEnode is NoneBase case: empty contributes 00
5Node 9d=2↑ COMBINE & RETURNL=0, R=0max(0, 0) + 11 (to Node 3)
6Node 20d=2⬇️ ENTERDescends into right subtree——
7Node 15d=3⬇️↑ LEAFL=0, R=0max(0, 0) + 11 (to Node 20)
8Node 7d=3⬇️↑ LEAFL=0, R=0max(0, 0) + 11 (to Node 20)
9Node 20d=2↑ COMBINE & RETURNL=1, R=1max(1, 1) + 12 (to Node 3)
10Node 3d=1↑ COMBINE & FINISHL=1, R=2max(1, 2) + 13 (Final Answer)
Trace Inputroot = [3,9,20,null,null,15,7]
Expected3
StepCall FrameDepthActionChild Subtree ReturnsCombine Step (max(L, R) + 1)Value Returned Upward
1Node 3d=1⬇️ ENTERSuspends; waits for children——
2Node 9d=2⬇️ ENTERDescends into left child——
39.leftd=3⬇️↑ BASEnode is NoneBase case: empty contributes 00
49.rightd=3⬇️↑ BASEnode is NoneBase case: empty contributes 00
5Node 9d=2↑ COMBINE & RETURNL=0, R=0max(0, 0) + 11 (to Node 3)
6Node 20d=2⬇️ ENTERDescends into right subtree——
7Node 15d=3⬇️↑ LEAFL=0, R=0max(0, 0) + 11 (to Node 20)
8Node 7d=3⬇️↑ LEAFL=0, R=0max(0, 0) + 11 (to Node 20)
9Node 20d=2↑ COMBINE & RETURNL=1, R=1max(1, 1) + 12 (to Node 3)
10Node 3d=1↑ COMBINE & FINISHL=1, R=2max(1, 2) + 13 (Final Answer)
Code Shape
Archetype Code Shape
Python
1if not root:
2 return 0
3left_depth = maxDepth(root.left)
4right_depth = maxDepth(root.right)
5return 1 + max(left_depth, right_depth)

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

Recursion asking a function to call itself feels circular the first time you see it — the trick is learning to trust it instead of trying to trace every call by hand.

🕵️ The Analogy: Sending Two Explorers and Waiting at the Door

Imagine you're standing at a node, and you need to know how deep the tree goes beneath you. You send one explorer down the left branch and one down the right branch, each with the exact same instructions: "go as deep as you can, then report back your depth." You don't follow them, and you don't need to know how they get their answer — you just wait at your own door. When they both report back, you take whichever explorer went deeper, add 1 for the step it took to reach you, and report that number to whoever sent you.

🔑 The Key Idea in the Code

"Trusting the recursion" means never asking how maxDepth(root.left) computed its answer — only that it did, correctly, for a strictly smaller tree. Every node in the tree plays the exact same "send two explorers, wait, combine" role, all the way down to the base case (None reports back 0, since an empty subtree has no depth to add).

  • Null child evaluation: Checking if not root.left and not root.right without handling if not root: return 0 first causes null dereference on empty inputs.

  • Off-by-one on the combine step: Returning max(left_depth, right_depth) without the + 1 for the current node undercounts depth at every level; the current node's own contribution must always be added on the way back up.

  • Confusing 0-indexed height with 1-indexed depth: Depth is 1-indexed (single node has depth 1), whereas some tree definitions treat the root as height 0.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

The statement asks for the number of nodes on the longest root-to-leaf path: a value a node can compute from its two subtrees' answers, the Bottom-Up DFS signal.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

max_depth(root) returns 1 + max(left_depth, right_depth), where left_depth = max_depth(root.left) and right_depth = max_depth(root.right); an empty subtree returns 0.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • The card's trap: the base case if not root: return 0 must be the value 1 + max(...) expects from an empty subtree.

  • Depth counts nodes, not edges: a single node has depth 1, so returning -1 for an empty subtree (the edge-count convention) is off by one here.

The 60-Second Interview Pitch

Say this out loud before you type a single line

I'd use Bottom-Up DFS. A node's depth depends only on its two subtrees, so I ask each child for its depth first and add one for the node itself on the way back up. Every call returns a finished answer for its own subtree, so the parent never looks deeper than those two numbers, and each node is visited exactly once. The one thing to get right is the base case: an empty subtree returns 0, which is exactly what one plus the max expects, so a leaf comes out as 1. If I returned minus one there, I'd be counting edges instead of nodes. That's O(N) time and O(H) for the recursion stack, where H is the height. The tree can have ten thousand nodes, and a chain that deep is past Python's default recursion limit, so in Python I'd switch to an explicit stack or raise the limit.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(N)

Look at the recursive function: def max_depth(root):. For every node in the binary tree, the function executes exactly 2 recursive calls (max_depth(root.left) and max_depth(root.right)) and performs O(1) constant-time arithmetic combining their results (1 + max(left_depth, right_depth)). Because each of the N tree nodes is visited and processed exactly once, total time is N · O(1) = O(N).

SPACE COMPLEXITY

O(H) recursion stack

Look at the recursion call stack: Each recursive call adds a new stack frame storing the local node pointer. The maximum number of simultaneous stack frames alive at any instant equals the maximum path depth from root to leaf, which is the tree height H. In a balanced binary tree, H = log2(N) -> O(log N) stack memory. In a worst-case skewed tree (linked list), H = N -> O(N) stack memory. We allocate zero heap objects, so auxiliary space is bounded by tree height O(H).

Formal Recurrence Relation

T(N) = T(N_left) + T(N_right) + O(1) = O(N)

Derivation Progression

Node Visitation

N nodes visited

Every node in the binary tree is entered and exited exactly once.

O(1) Work Per Frame

1 + max(left_depth, right_depth)

Combining child subproblem depths requires a single addition and max comparison in O(1).

Tree Recurrence

T(N) = T(N_left) + T(N_right) + O(1) = O(N)

One O(1) frame per node and one per empty child (N + 1 of them), so 2N + 1 calls on any shape: a chain and a balanced tree of the same size cost the same.

Variable Definitions

NNN

Total number of nodes in the binary tree

HHH

Tree height (log N in balanced tree, N in skewed tree)

Memory Architecture & Bounds

🟣 Call Stack

O(H) Recursion stack storing tree height H frames (O(log N) balanced, O(N) skewed)

🔵 Auxiliary Heap

O(1) Zero heap allocations

🟢 Output Space

O(1) Returns integer tree depth

Boundary Best / Worst Cases

Best Case

O(N)O(N)O(N) time with O(log⁡N)O(\log N)O(logN) stack on balanced tree.

Average Case

O(N)O(N)O(N) time with O(log⁡N)O(\log N)O(logN) stack.

Worst Case

O(N)O(N)O(N) time with O(N)O(N)O(N) stack on skewed tree (linked list shape).

Graph & Tree Traversal Frontier

Graph & Tree Traversal Frontier
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "maximum depth of binary tree", "number of nodes along longest path from root to leaf". A node's answer comes only from its two subtrees' answers: Bottom-Up DFS, with no global state to share between calls.

CONSTRAINTS & BOUNDS

0≤N≤1040 \le N \le 10^40≤N≤104. Time budget is strictly O(N)O(N)O(N) visiting each node once. Space budget is O(H)O(H)O(H) stack frames (O(log⁡N)O(\log N)O(logN) on balanced trees, O(N)O(N)O(N) worst-case on degenerate lists).

FAANG PRODUCTION TRAPS & EDGE CASES

A chain of 10410^4104 nodes, the LeetCode maximum, is already past CPython's default recursion limit of 1000: raise the limit, or walk with an explicit stack (or level by level with a queue).

Theory Context•Depth-First Search (DFS)
EasyLC 104

Maximum Depth of Binary Tree (LeetCode 104)

Target Frequency:MetaAmazonApple

You're handed the root of a binary tree and asked how tall it is: its maximum depth.

The maximum depth counts the nodes on the single longest chain running from the root all the way down to whichever leaf sits farthest away.

Worked Examples

Example 1
Input:root = [3,9,20,null,null,15,7]
Output:3
9315207
Explanation: The longest path is 3 -> 20 -> 15 (or 7), which has 3 nodes.
Example 2
Input:root = [1,null,2]
Output:2
12
Explanation: The longest path is 1 -> 2, which has 2 nodes.

⚖️Formal Constraints & Bounds

  • The number of nodes in the tree is in the range [0, 104].

  • -100 <= Node.val <= 100

Deep-Dive & Conceptual Insights

Core Insight

Tree problems naturally decompose into identical subproblems on the left and right subtrees.

Real-World Scenario & Production Applications

Directory tree depth calculation in filesystems, DOM tree depth traversal in browser rendering engines.

Step-by-Step Execution Trace Table

StepCall FrameDepthActionChild Subtree ReturnsCombine Step (max(L, R) + 1)Value Returned Upward
1Node 3d=1⬇️ ENTERSuspends; waits for children——
2Node 9d=2⬇️ ENTERDescends into left child——
39.leftd=3⬇️↑ BASEnode is NoneBase case: empty contributes 00
49.rightd=3⬇️↑ BASEnode is NoneBase case: empty contributes 00
5Node 9d=2↑ COMBINE & RETURNL=0, R=0max(0, 0) + 11 (to Node 3)
6Node 20d=2⬇️ ENTERDescends into right subtree——
7Node 15d=3⬇️↑ LEAFL=0, R=0max(0, 0) + 11 (to Node 20)
8Node 7d=3⬇️↑ LEAFL=0, R=0max(0, 0) + 11 (to Node 20)
9Node 20d=2↑ COMBINE & RETURNL=1, R=1max(1, 1) + 12 (to Node 3)
10Node 3d=1↑ COMBINE & FINISHL=1, R=2max(1, 2) + 13 (Final Answer)
Trace Inputroot = [3,9,20,null,null,15,7]
Expected3
StepCall FrameDepthActionChild Subtree ReturnsCombine Step (max(L, R) + 1)Value Returned Upward
1Node 3d=1⬇️ ENTERSuspends; waits for children——
2Node 9d=2⬇️ ENTERDescends into left child——
39.leftd=3⬇️↑ BASEnode is NoneBase case: empty contributes 00
49.rightd=3⬇️↑ BASEnode is NoneBase case: empty contributes 00
5Node 9d=2↑ COMBINE & RETURNL=0, R=0max(0, 0) + 11 (to Node 3)
6Node 20d=2⬇️ ENTERDescends into right subtree——
7Node 15d=3⬇️↑ LEAFL=0, R=0max(0, 0) + 11 (to Node 20)
8Node 7d=3⬇️↑ LEAFL=0, R=0max(0, 0) + 11 (to Node 20)
9Node 20d=2↑ COMBINE & RETURNL=1, R=1max(1, 1) + 12 (to Node 3)
10Node 3d=1↑ COMBINE & FINISHL=1, R=2max(1, 2) + 13 (Final Answer)
Code Shape
Archetype Code Shape
Python
1if not root:
2 return 0
3left_depth = maxDepth(root.left)
4right_depth = maxDepth(root.right)
5return 1 + max(left_depth, right_depth)

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

Recursion asking a function to call itself feels circular the first time you see it — the trick is learning to trust it instead of trying to trace every call by hand.

🕵️ The Analogy: Sending Two Explorers and Waiting at the Door

Imagine you're standing at a node, and you need to know how deep the tree goes beneath you. You send one explorer down the left branch and one down the right branch, each with the exact same instructions: "go as deep as you can, then report back your depth." You don't follow them, and you don't need to know how they get their answer — you just wait at your own door. When they both report back, you take whichever explorer went deeper, add 1 for the step it took to reach you, and report that number to whoever sent you.

🔑 The Key Idea in the Code

"Trusting the recursion" means never asking how maxDepth(root.left) computed its answer — only that it did, correctly, for a strictly smaller tree. Every node in the tree plays the exact same "send two explorers, wait, combine" role, all the way down to the base case (None reports back 0, since an empty subtree has no depth to add).

  • Null child evaluation: Checking if not root.left and not root.right without handling if not root: return 0 first causes null dereference on empty inputs.

  • Off-by-one on the combine step: Returning max(left_depth, right_depth) without the + 1 for the current node undercounts depth at every level; the current node's own contribution must always be added on the way back up.

  • Confusing 0-indexed height with 1-indexed depth: Depth is 1-indexed (single node has depth 1), whereas some tree definitions treat the root as height 0.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

The statement asks for the number of nodes on the longest root-to-leaf path: a value a node can compute from its two subtrees' answers, the Bottom-Up DFS signal.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

max_depth(root) returns 1 + max(left_depth, right_depth), where left_depth = max_depth(root.left) and right_depth = max_depth(root.right); an empty subtree returns 0.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • The card's trap: the base case if not root: return 0 must be the value 1 + max(...) expects from an empty subtree.

  • Depth counts nodes, not edges: a single node has depth 1, so returning -1 for an empty subtree (the edge-count convention) is off by one here.

The 60-Second Interview Pitch

Say this out loud before you type a single line

I'd use Bottom-Up DFS. A node's depth depends only on its two subtrees, so I ask each child for its depth first and add one for the node itself on the way back up. Every call returns a finished answer for its own subtree, so the parent never looks deeper than those two numbers, and each node is visited exactly once. The one thing to get right is the base case: an empty subtree returns 0, which is exactly what one plus the max expects, so a leaf comes out as 1. If I returned minus one there, I'd be counting edges instead of nodes. That's O(N) time and O(H) for the recursion stack, where H is the height. The tree can have ten thousand nodes, and a chain that deep is past Python's default recursion limit, so in Python I'd switch to an explicit stack or raise the limit.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(N)

Look at the recursive function: def max_depth(root):. For every node in the binary tree, the function executes exactly 2 recursive calls (max_depth(root.left) and max_depth(root.right)) and performs O(1) constant-time arithmetic combining their results (1 + max(left_depth, right_depth)). Because each of the N tree nodes is visited and processed exactly once, total time is N · O(1) = O(N).

SPACE COMPLEXITY

O(H) recursion stack

Look at the recursion call stack: Each recursive call adds a new stack frame storing the local node pointer. The maximum number of simultaneous stack frames alive at any instant equals the maximum path depth from root to leaf, which is the tree height H. In a balanced binary tree, H = log2(N) -> O(log N) stack memory. In a worst-case skewed tree (linked list), H = N -> O(N) stack memory. We allocate zero heap objects, so auxiliary space is bounded by tree height O(H).

Formal Recurrence Relation

T(N) = T(N_left) + T(N_right) + O(1) = O(N)

Derivation Progression

Node Visitation

N nodes visited

Every node in the binary tree is entered and exited exactly once.

O(1) Work Per Frame

1 + max(left_depth, right_depth)

Combining child subproblem depths requires a single addition and max comparison in O(1).

Tree Recurrence

T(N) = T(N_left) + T(N_right) + O(1) = O(N)

One O(1) frame per node and one per empty child (N + 1 of them), so 2N + 1 calls on any shape: a chain and a balanced tree of the same size cost the same.

Variable Definitions

NNN

Total number of nodes in the binary tree

HHH

Tree height (log N in balanced tree, N in skewed tree)

Memory Architecture & Bounds

🟣 Call Stack

O(H) Recursion stack storing tree height H frames (O(log N) balanced, O(N) skewed)

🔵 Auxiliary Heap

O(1) Zero heap allocations

🟢 Output Space

O(1) Returns integer tree depth

Boundary Best / Worst Cases

Best Case

O(N)O(N)O(N) time with O(log⁡N)O(\log N)O(logN) stack on balanced tree.

Average Case

O(N)O(N)O(N) time with O(log⁡N)O(\log N)O(logN) stack.

Worst Case

O(N)O(N)O(N) time with O(N)O(N)O(N) stack on skewed tree (linked list shape).

Graph & Tree Traversal Frontier

Graph & Tree Traversal Frontier
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "maximum depth of binary tree", "number of nodes along longest path from root to leaf". A node's answer comes only from its two subtrees' answers: Bottom-Up DFS, with no global state to share between calls.

CONSTRAINTS & BOUNDS

0≤N≤1040 \le N \le 10^40≤N≤104. Time budget is strictly O(N)O(N)O(N) visiting each node once. Space budget is O(H)O(H)O(H) stack frames (O(log⁡N)O(\log N)O(logN) on balanced trees, O(N)O(N)O(N) worst-case on degenerate lists).

FAANG PRODUCTION TRAPS & EDGE CASES

A chain of 10410^4104 nodes, the LeetCode maximum, is already past CPython's default recursion limit of 1000: raise the limit, or walk with an explicit stack (or level by level with a queue).

© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•