Free Handbook · Runs in your browser

Problem Solving

How to read a problem, break it into input → steps → output, test with tiny cases, reason about Big-O in plain English, and the eight patterns — two pointers, sliding window, hash map, stack, recursion, sorting, BFS/DFS, dynamic programming — each as runnable JavaScript.

0 / 111 lessons🔥 0 day streak
ShareXLinkedIn

Module 12 · what you'll be able to do

  • Turn a vague problem into a contract with edge cases before writing code
  • Say the brute force out loud, then find the repeated work
  • Estimate Big-O from the shape of the loops
  • Recognise which of the eight patterns a problem is secretly about
  • Work an interview problem from statement to tested solution
01

How to read a problem

Most wrong solutions come from solving the wrong problem. Before code, spend two minutes pinning down exactly what goes in, what comes out, and what happens at the edges. Interviewers watch for this step; it is also what separates a ticket you finish from one you redo.

  1. 1
    Restate it in one sentence

    "Given an array of daily prices, return the maximum profit from one buy followed by one later sell." If you cannot say it, you cannot code it.

  2. 2
    Pin the contract

    Input: array of numbers, length 0…10⁵, prices ≥ 0. Output: number ≥ 0; 0 if no profit is possible. Empty → 0.

  3. 3
    Work a tiny example by hand

    [7, 1, 5, 3, 6, 4] → buy at 1, sell at 6 → 5. Now you have a test.

  4. 4
    List the edge cases

    Empty; one price; always falling ([5, 4, 3] → 0); all equal; the best buy is the last day.

  5. 5
    Say the brute force out loud

    "Try every buy day and every later sell day" — O(n²). Correct first, fast second. Then ask what work is repeated.

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
ok   [7,1,5,3,6,4] → 5
ok   [] → 0
ok   [5] → 0
ok   [5,4,3] → 0
ok   [2,2,2] → 0
ok   [3,1,10] → 9
Your turn
Change the contract: you may buy and sell as many times as you like (never holding two). Write the tests first, then the one-pass solution.
02

Big-O in plain English

Big-O answers one question: when the input grows, how much more work is there? O(1) — the same. O(log n) — barely more (halving). O(n) — proportionally more. O(n log n) — a bit worse than proportional (good sorts). O(n²) — four times the work for twice the data (nested loops). O(2ⁿ) — hopeless past n ≈ 30. You estimate it by looking at the shape of the loops, and you use it to know whether a solution will survive real data.

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
hasDuplicateSlow   slow (100s of ms)
hasDuplicateFast   fast (a few ms)
{ n: 8, squared: 64, log: 3 } { n: 1024, squared: 1048576, log: 10 }
Space works the same way: a Set of every item is O(n) extra memory; two variables is O(1).
Shape of the codeBig-On = 1,000,000 means…
Index, Map/Set lookup, push/popO(1)1 step
Halve the input each step (binary search)O(log n)~20 steps
One loop over the inputO(n)1M steps
Sort, or a loop with a log-step insideO(n log n)~20M steps
Loop inside a loop over the same inputO(n²)10¹² steps — minutes to hours
Try every subsetO(2ⁿ)never finishes
Quick check

for (const x of a) if (b.includes(x)) … where a and b both have n items. Big-O?

03

Pattern 1 & 2: two pointers, sliding window

Two pointers: walk from both ends (or two speeds) of a sorted array or a linked list, moving one pointer based on a comparison — O(n) instead of O(n²). Sliding window: a contiguous range [left, right] that expands and shrinks; each element enters and leaves once. The words that give it away: "pair that sums to", "longest substring", "subarray of size k", "in a sorted array".

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
[ 4, 6 ] null
3 1 0
9
true false
Your turn
Write removeDuplicatesSorted(nums) in place with two pointers (a "write" index and a "read" index), returning the new length.
04

Pattern 3 & 4: hash map, stack

Hash map (Map / Set / object): trade memory for time by remembering what you have seen — counts, groups, "the complement of this number", "the index where I last saw x". It turns almost every O(n²) "compare each to each" into O(n). Stack: when the most recent thing matters — matching brackets, undo, "next greater element", parsing anything nested.

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
[ 0, 1 ] [ 0, 1 ]
[ [ 'eat', 'tea', 'ate' ], [ 'tan', 'nat' ], [ 'bat' ] ]
[ [ 'i', 4 ], [ 's', 4 ] ]
"([]{})"   true
"([)]"     false
"(("       false
""         true
[ 4, 2, 4, -1, -1 ]
Your turn
Write firstNonRepeating(str) — the first character that appears exactly once — with one Map and two passes.
05

Pattern 5 & 6: recursion / backtracking, sorting

Recursion / backtracking: for "all combinations", "all permutations", "can we reach", "explore a tree" — make a choice, recurse, undo the choice. Sorting as the first move: a surprising number of problems become one pass once the input is sorted — merging intervals, finding pairs, deduplicating, "closest values". Sorting costs O(n log n), which is cheap.

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
[ [ 1, 2, 3 ], [ 1, 2 ], [ 1, 3 ], [ 1 ], [ 2, 3 ], [ 2 ], [ 3 ], [] ]
[ 'abc', 'acb', 'bac', 'bca', 'cab', 'cba' ]
[ [ 1, 4 ], [ 5, 8 ], [ 9, 10 ] ]
[ [ 'ada', 36, 'data' ], [ 'cy', 36, 'infra' ], [ 'bob', 28, 'infra' ] ]
[ 'ada', 36, 'data' ]
Your turn
Write combinations(items, k) — all subsets of exactly k items — by adding a size check to the backtracking above.
06

Pattern 7 & 8: BFS / DFS, dynamic programming

BFS (queue): shortest path, fewest steps, level by level. DFS (stack or recursion): reachability, connected components, cycle detection, exhaustive search. Grids are graphs where each cell's neighbours are up/down/left/right. Dynamic programming: when the brute-force recursion recomputes the same sub-problems, cache them (memoise) or fill a table bottom-up. Module 13 goes deeper on all three.

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
[ 'A', 'B', 'D', 'F' ]
[ 'C', 'D', 'E', 'F' ]
3
20365011074
6 -1
How to spot DP
The words minimum / maximum / how many ways / longest / is it possible, plus a choice at each step (take or skip, one step or two). If your recursion prints the same arguments twice, memoise it — that is the whole trick.
07

Worked examples: from statement to solution

Two problems the way they arrive at work — a paragraph, not a LeetCode title — solved with the process from the first lesson. Notice that the pattern is chosen by naming the repeated work in the brute force.

javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
[ 'ada' ]
[]
[]
javascriptEdit it. ⌘/Ctrl + Enter runs.
You should see
ERROR [ [ 'db timeout', 2 ], [ 'disk full', 2 ] ]
INFO [ [ 'started', 2 ], [ 'done', 1 ] ]
Your turn
Extend it: lines can have a timestamp prefix ("2026-09-20T10:00:00Z ERROR db timeout"). Detect and skip it without breaking the old format.

Graded practice for JavaScript is coming to /practice; until then, the Python problems and SQL problems exercise the same patterns and are language-agnostic in their thinking. Module 13 builds the structures these patterns run on.

Mid-levelYou are given an array of a million integers and asked whether any two sum to a target. Walk me through your approach.

Brute force is every pair, O(n²) — a trillion operations, too slow. Two options: sort then two pointers, O(n log n) and O(1) extra space; or one pass with a Set of seen values checking for target - x, O(n) time and O(n) space. I would pick the Set unless memory is constrained, mention integer overflow is not an issue in JS below 2⁵³, and confirm whether duplicates and the same element twice count.

What they are really testing: That you name the brute force, know two better patterns, and can discuss the trade-off.

Finish the JavaScript handbook, then get hired

Sit the exam for your certificate, run your resume through the ATS checker, and see the jobs that ask for exactly this.

Check my resume
Found this course useful? Share it.
ShareXLinkedIn

Comments

0

Join the conversation. Sign in to leave a comment — we'd love to hear your thoughts.