Code Challenges

The bar: you can solve an intermediate-level coding problem cold — no AI, no notes — in JavaScript or Python, explain its time and space cost out loud, and finish inside a clock.

This is the gate. Everything before this taught you syntax, tooling, and habits. Now you prove you can actually think in code. The rep count is high on purpose: fundamental data structures and algorithm patterns don't stick from reading about them, they stick from grinding problems until the shapes become reflex.

One rule that matters more than any other here — no AI tools. You solve these from your own head. Autocomplete and a chat window are fine for shipping features later, but the interview room and the 2 a.m. production incident don't have them. If you can't reason through a two-pointer sweep without a model handing it to you, you haven't learned it. Clear intermediate LeetCode under your own power or you don't move to Phase 2.

8.1 Data Structures

Objective: understand the fundamental data structures and know when to reach for each one.

A data structure is just a way to lay out data so the operations you need are cheap. Arrays and strings give you indexed, ordered access. Objects, dictionaries, and hash maps give you near-instant lookup by key — the single most useful trick in this whole module. Sets give you the same lookup but only care whether something exists, which is exactly what you want for uniqueness checks.

Stacks (last-in, first-out) and queues (first-in, first-out) show up any time order of processing matters — undo history, breadth-first traversal, parsing. Linked lists teach you pointer thinking, and trees and graphs are where the harder problems live. You don't need to master graph theory yet; you need to recognize the shapes.

The common trap: forcing an array where a hash map belongs, then scanning it in a loop. That's how an O(n) problem quietly becomes O(n²).

Drill:

  • Build and traverse an array, then a dict/object, then a set in both languages.
  • Implement a stack and a queue from scratch (push/pop, enqueue/dequeue).
  • Walk a singly linked list; reverse it.
  • Sketch a binary tree and a small graph; identify nodes, edges, and children.

8.2 Algorithm Patterns

Objective: recognize the recurring patterns and apply them on sight.

Most intermediate problems are one of a dozen patterns wearing a costume. Learn the patterns and you stop solving each problem from zero. Two pointers walks a sorted array from both ends or at two speeds. Sliding window tracks a moving range to avoid recomputing overlaps. Frequency counters trade memory for speed by tallying with a hash map instead of nesting loops.

Divide and conquer splits a problem into halves you solve independently (binary search, merge sort). Recursion expresses a problem in terms of a smaller version of itself. Dynamic programming is recursion plus memory — you cache subproblem answers so you never compute the same thing twice.

The gotcha: reaching for brute force, getting a correct-but-slow answer, and stopping there. Interviewers and real systems care about the second solution. Train yourself to ask "which pattern kills the nested loop?"

Drill:

  • Solve a pair-sum on a sorted array with two pointers.
  • Find the longest substring without repeats using a sliding window.
  • Count anagram groups with a frequency counter.
  • Write one recursive solution, then convert it to a memoized dynamic-programming version.

8.3 Complexity Analysis

Objective: analyze the time and space cost of a solution and defend it.

Big-O describes how your runtime or memory grows as the input grows. It's not about milliseconds; it's about shape — O(1), O(log n), O(n), O(n log n), O(n²). You need to name the complexity of anything you write without hesitating, because "it works" is only half the answer an engineer gives.

Analyze time complexity by counting how the work scales with input, and space complexity by counting the extra memory you allocate — a hash map you build is space you spend. Know the difference between best, average, and worst case: a hash lookup is O(1) average but O(n) worst case when everything collides.

The mistake self-taught engineers make is optimizing blind. Read the constraints first. If n is 20, an exponential solution is fine; if n is a million, O(n²) will time out. Optimize for the constraint you were given, not for elegance.

Drill:

  • State the time and space complexity of every problem you solve, out loud.
  • Classify snippets as O(1), O(log n), O(n), O(n log n), O(n²).
  • For one problem, name its best, average, and worst case and explain what triggers each.

8.4 Problem-Solving Strategy

Objective: attack any technical problem with a repeatable, systematic process.

Panicking and typing is how you fail an assessment. A process is how you pass one. First, understand the problem — restate it in your own words and pin down inputs, outputs, and edge cases. Second, work a concrete example by hand, including an empty input and a degenerate one. Third, break the solution down into plain-language steps before a single line of code.

Then code the solution, keeping it simple and correct before clever. Test and debug against your examples plus the edges you found. Only then optimize — get it working, then get it fast. Trying to write the optimal solution in one pass is the surest way to freeze.

The habit to build: narrate. Talking through your reasoning catches your own bugs and, in a real interview, shows the room how you think when you don't know the answer yet.

Drill:

  • For each problem, write inputs/outputs/edge cases before coding.
  • Trace one example by hand on paper first.
  • Draft plain-English steps, then translate to code.
  • Test against edges (empty, single element, duplicates) before calling it done.

8.5 String and Array Problems

Objective: solve the common string and array challenges in both JavaScript and Python.

Strings and arrays are the bread and butter of the easy-to-medium range, and they're where two-pointer and sliding-window patterns pay off most. You'll reverse, rotate, and manipulate sequences; detect palindromes and anagrams; and hunt for subarrays and substrings that satisfy some condition.

Two-sum and its variations deserve special attention — they're the canonical "array plus hash map beats the nested loop" lesson, and interviewers love them. Merge and sort operations round it out: merging two sorted lists, sorting with a custom comparator, deduplicating in place.

Watch the language gap. JavaScript strings are immutable and its sort() defaults to lexicographic — [10, 2].sort() gives [10, 2], not what you meant. Python strings are immutable too, but slicing and negative indexing make manipulation far terser. Know each language's sharp edges cold.

Drill:

  • Reverse and rotate an array in place; reverse a string.
  • Detect a palindrome and check whether two strings are anagrams.
  • Solve two-sum with a hash map in O(n), then a variation (three-sum, two-sum on a sorted array).
  • Merge two sorted arrays; sort with a custom comparator.

8.6 Object and Map Problems

Objective: use hash-based structures to solve problems efficiently.

When a problem smells like "have I seen this before?" or "how many times?", the answer is almost always a hash map or set. Frequency counting tallies occurrences in one pass. Grouping and categorization buckets items by a computed key — sorted letters for anagrams, first character, remainder, whatever. Deduplication is a set membership check.

Caching and memoization store computed results so repeated calls are free; this is the engine under dynamic programming and a real-world performance tool. Key-value transformations reshape data from one form to another — the everyday work of turning an API response into what your UI needs.

The trap here is subtle: hash lookups are O(1) on average, but building the map costs memory. On a constrained problem you sometimes trade that memory back for a two-pointer approach. Know that you're making the trade.

Drill:

  • Count character or element frequencies with a hash map.
  • Group a list of words into anagram buckets by a computed key.
  • Deduplicate a list with a set.
  • Memoize a recursive function and measure the difference.

8.7 Recursion and Trees

Objective: think recursively and traverse tree structures with confidence.

Recursion is a function calling itself on a smaller input until it hits a base case that stops the descent. Get the base case wrong and you get infinite recursion or a wrong answer — nail it first, every time, then handle the recursive case. Trees are where recursion feels natural because a tree is itself defined recursively: a node with subtrees.

Learn both traversals. DFS (depth-first) dives down a branch before backtracking — natural to write recursively or with a stack. BFS (breadth-first) sweeps level by level using a queue. Binary search trees keep values ordered so lookups are O(log n) when balanced. Path and sum problems ask you to accumulate state as you descend. Backtracking is DFS that undoes its choices when a branch fails — the basis for permutations, combinations, and constraint puzzles.

The classic stumble is forgetting to return the recursive result, or mutating shared state across branches without cleaning up. Draw the call tree when you're stuck.

Drill:

  • Write a recursive function with an explicit base case (factorial, then Fibonacci).
  • Traverse a binary tree with DFS (recursive) and BFS (queue).
  • Insert into and search a binary search tree.
  • Solve a root-to-leaf path-sum problem; write one simple backtracking solution.

8.8 JavaScript Challenges

Objective: solve problems fluently and specifically in JavaScript.

This is volume work: 50-plus easy and 25-plus medium LeetCode problems, in JavaScript, under your own power. The goal is fluency — array and string manipulation, object and map problems — until the language stops being the obstacle and the problem is the only thing you're thinking about.

Add timed practice sessions as you go. Correctness without a clock is a study habit; correctness against a clock is the actual skill the assessment measures. Know your JS toolkit cold: Map and Set over plain objects when keys aren't strings, Array.from, reduce, and the sort() comparator gotcha from 8.5.

Drill:

  • Grind 50+ easy and 25+ medium problems in JavaScript.
  • Reach for Map/Set, reduce, and spread/destructuring without looking them up.
  • Run timed sessions — one easy problem in under 15 minutes, one medium in under 30.

8.9 Python Challenges

Objective: solve problems fluently and specifically in Python.

Same volume, second language: 50-plus easy and 25-plus medium, in Python. Doing the reps in both languages is what makes the patterns portable — you learn the algorithm, not just one syntax for it. Focus on list and string manipulation, dictionary and set problems.

Python rewards knowing its standard library. collections.Counter collapses a frequency count to one line; defaultdict removes key-existence checks; dict and set comprehensions reshape data tersely; negative indexing and slicing make array work clean. Keep timing your sessions here too.

Drill:

  • Grind 50+ easy and 25+ medium problems in Python.
  • Use Counter, defaultdict, comprehensions, and slicing idiomatically.
  • Run timed sessions matching the JS pace.

8.10 Hands-On Lab: Assessment Gate

Objective: prove, under a clock and without assistance, that you're ready for Phase 2.

What you ship

A timed coding assessment: 3 problems in 90 minutes. One in JavaScript, one in Python, and one language-agnostic problem you solve in whichever language you choose. No AI tools, no notes — from your own head, exactly as an interview or an incident demands.

Each solution must be correct, and you must be able to state its time and space complexity. This gate is pass/fail: clear it and you advance to Phase 2. Fall short and you go back to the reps in 8.8 and 8.9 until the patterns are reflex, then sit the gate again.

On the VWC codebase

Phase 2 is where this pays off — you'll ship real features to real veterans on the Vets Who Code platform, a Next.js and TypeScript app backed by Prisma and Postgres. The daily work there is feature engineering, not LeetCode, but the muscle you build here is exactly what carries you through it: reading a problem carefully, choosing the right data structure, and reasoning about cost before you commit code to a codebase other people depend on.