Cheat sheet · Computer Science Foundations Interviewers Assume

CS Foundations cheat sheet

The machine under your JavaScript: memory, caches, floats, text, bits, counting, hard problems and string search. Numbers quoted from the lessons are local measurements, so say "about" in an interview.

Read the full series →

blogs · jp-blogs.vercel.app/cheatsheets/series/cs-foundations

How JavaScript runs (V8)Lesson 0 →

  • Pipeline: parse, bytecode (Ignition), then optional machine-code tiers (Sparkplug, Maglev, TurboFan).
  • A JIT compiles hot code while the program runs, guessing types. A broken guess is a deopt: back to the interpreter.
  • Keep types and object shapes stable in hot code. Profile before you worry.
  • Local test: the same loop took 388 ms with the JIT and 2454 ms with --jitless.
ApproachGoodBad
Ahead-of-time (C, Rust)Fast to runSlow build, one binary per CPU
InterpretStarts at onceSlow per step
JIT (V8, Java)Fast start, fast hot codeComplex, spends memory and CPU

Stack, heap and referencesLesson 0 →

Stack
One frame per active call: arguments, locals, return place
Heap
Objects, arrays, closures. Variables hold references to them
Stack overflow
RangeError: about 12,500 frames (1 arg), 5,000 (6 args) locally
Pass by value
For objects the value is a reference (call by sharing)
Garbage collection
Frees what is unreachable from roots. A forgotten cache still leaks
Typed array
Flat bytes outside the JS heap. Several views can share one buffer

Watch out: V8 has no tail call optimisation. A correct recursive DFS on 100,000 nodes can still crash. Use an explicit stack.

The memory pyramidLesson 1 →

LevelTypical latency
L1 cache (32 to 64 KB)about 1 ns
L2 cacheabout 3 to 5 ns
L3 cache (shared)about 10 to 40 ns
RAMabout 80 to 100 ns
SSD random readabout 10 to 100 microseconds
Network, same data centreabout 0.5 ms
Network, across the worldabout 100 to 200 ms

Tip: Remember the ratios, not the digits. Each level down is roughly 10 to 100 times slower.

Write cache-friendly codeLesson 1 →

  • Memory loads in 64-byte cache lines, so one Float64Array read brings 8 neighbours.
  • Spatial locality: use neighbours. Temporal locality: reuse a value soon.
  • 4096 x 4096 matrix: 37 ms row by row, 314 ms column by column. A 512 KB matrix showed only 1.2x.
  • Random access cost about 11 times sequential. One field of 2 million records: 4.5 ms struct of arrays, 21 ms array of objects.
for (let r = 0; r < n; r++)
  for (let c = 0; c < n; c++)
    sum += m[r * n + c];

Two O(n²) loops can differ 10 times; Big-O hides the memory pattern.

Floating pointLesson 2 →

Double partBitsJob
Sign10 positive, 1 negative
Exponent11Power of 2, bias 1023
Mantissa52Digits after an implied leading 1
  • 0.1 + 0.2 is 0.30000000000000004: 1/10 is a repeating fraction in binary.
  • Integers are exact up to 2**53 - 1. Gaps between doubles grow with the size.
  • Number.EPSILON is 2^-52, valid near 1 only.
const near = (a, b, eps = 1e-9) =>
  Math.abs(a - b) <=
  eps * Math.max(1, Math.abs(a),
                 Math.abs(b));

Float traps and moneyLesson 2 →

NaN
Never equals itself. Use Number.isNaN(x)
0 and -0
0 === -0 but Object.is(0, -0) is false
(1.005).toFixed(2)
"1.00": stored as 1.00499999999999989
Math.floor((0.1+0.7)*10)
7, not 8. Use Math.round
Float addition
Not associative: order changes last digits
sort((a, b) => a - b)
Breaks on NaN: the comparator returns NaN

Tip: Money: integer cents, round once on the way in, give the remainder to a part when splitting. BigInt for huge values. IDs past 2^53 travel as strings.

Four sizes of a characterLesson 3 →

LayerCountsFamily emoji
Grapheme clusterWhat the reader sees1
Code pointUnicode number5
UTF-16 unitlength, [i], slice8
UTF-8 byteFile or network size18
  • "😀".length is 2 (surrogate pair). [...s] goes by code point, Intl.Segmenter by grapheme.
  • UTF-8 uses 1 to 4 bytes: 0xxxxxxx, 110xxxxx 10xxxxxx, and so on. ASCII is unchanged.

Text: normalise, sort, cutLesson 3 →

s.normalize("NFC")
Compare and store text in this form
NFKC
Loose match only: fi to fi, ① to 1. Loses data
new Intl.Collator(loc)
Sort for users. Default sort() uses code units
TextDecoder fatal: true
Throw on bad bytes instead of silent U+FFFD
s.isWellFormed()
False when a lone surrogate exists

Watch out: Mojibake (café) is a wrong decode: fix the declared encoding. Truncate on grapheme boundaries, never mid-pair. split("").reverse() breaks emoji.

Bits in JavaScriptLesson 4 →

GoalExpression
Read, set bit i(x >> i) & 1, x | (1 << i)
Clear, toggle bit ix & ~(1 << i), x ^ (1 << i)
Power of twon > 0 && (n & (n - 1)) === 0
Clear lowest set bitn & (n - 1)
Keep lowest set bitn & -n
Find the single numberXOR everything; pairs cancel
  • Bitwise operators use 32-bit signed ints: 1 << 32 is 1, 1 << 31 is negative, >>> 0 makes unsigned.
  • >> keeps the sign, >>> fills with zeros. -1 >>> 1 is 2147483647.
  • Two's complement: -x === ~x + 1. Signed 8-bit range is -128 to 127.

Watch out: Odd test: x % 2 === 1 fails for -7. Use x % 2 !== 0 or (x & 1) === 1. Wrap bitwise ops in parentheses.

Counting and chanceLesson 5 →

Ordered?Repeats?Count
YesNon! or n x (n-1) x ... x (n-k+1)
NoNoC(n, k)
YesYesn^k
NoYesC(n + k - 1, k)
  • C(n, k) = C(n-1, k-1) + C(n-1, k). MISSISSIPPI: 11! / (4! 4! 2!) = 34,650.
  • Inclusion-exclusion, or count the opposite. Divisible by 2, 3 or 5 up to 1000: 734.
  • Birthday: a collision comes near sqrt(d). 23 people about 50.7%; a 32-bit hash about 77,000 items.
  • Expected value adds even without independence. Coupon collector for 6 faces: 14.7 rolls.
  • 99% sensitive, 5% false positives, 1% base rate: a positive is real only about 16.7%.

Shuffle and sampleLesson 5 →

for (let i = a.length - 1; i > 0; i--) {
  const j = Math.floor(
    Math.random() * (i + 1));
  [a[i], a[j]] = [a[j], a[i]];
}

Fisher-Yates: O(n), every order has chance 1/n!.

  • sort(() => Math.random() - 0.5) is biased: the comparator is inconsistent.
  • Reservoir sampling (stream, one pass): keep the first k, then replace slot j when j < k. For k = 1 replace with chance 1/i.

P, NP and hard problemsLesson 6 →

ClassMeansExample
PQuick to solveSorting, shortest path, 2-SAT
NPQuick to checkAll of P and below
NP-completeIn NP, hardest of NPSAT, subset sum, 3-colouring
NP-hardAt least that hardCheapest tour, best knapsack
SituationApproach
n up to about 20Brute force or bitmask
n up to 25 to 30DP over subsets (Held-Karp)
Numbers are smallPseudo-polynomial DP
Speed plus a guaranteeApproximation
Large and messyHeuristic or a solver

Tip: "It is NP-hard" starts the answer. Next: input size, easy variant (2-colouring?), then exact, DP, approximation or heuristic.

Search for a stringLesson 7 →

NeedUseTime
Real codeincludes / indexOfbuilt in
One pattern, worst caseKMP or ZO(n + m)
Many same-length patternsRabin-KarpO(n + m) avg
Many different lengthsAho-CorasickO(n + total + matches)
Short textNaiveO(n x m) worst
function fail(p) {
  const f = [0];
  for (let i = 1, k = 0; i < p.length;
       i++) {
    while (k > 0 && p[i] !== p[k])
      k = f[k - 1];
    if (p[i] === p[k]) k++;
    f[i] = k;
  }
  return f;
}

ababaca gives 0 0 1 2 3 0 1. On a mismatch use k = f[k - 1], never k = 0.

Watch out: Rabin-Karp must verify on equal hashes (aa and ht collide mod 101). Indexes count UTF-16 units, not letters.

Interview one-linersLesson 2 →

QuestionShort answer
Compiled or interpreted?Both: bytecode first, hot code JIT-compiled.
Pass by value or reference?By value; for objects the value is a reference.
Why is 0.1 + 0.2 off?Binary doubles cannot hold 1/10 exactly.
Why is row-major faster?Cache lines hold neighbours; columns waste them.
"😀".length?2: UTF-16 units. Use [...s] or Intl.Segmenter.
Is a number a power of two?n > 0 && (n & (n - 1)) === 0.
Shuffle fairly?Fisher-Yates, not a random comparator.
Subset sum DP vs NP-complete?Pseudo-polynomial: polynomial in the value, not the digits.

A cheat sheet is a reminder, not a teacher. Each card links to the lesson that explains it step by step.