latency.lab
Algorithms · Topic 17

Math & Geometry

Level: foundationTool: Decomposition, overflow-safe arithmetic, and exact geometryTime: ~75 min

By the end you can

Math & Geometry problems don't share one data structure the way graphs or intervals do — what actually unites them is a mindset: decompose a problem that looks 2D, huge, or overflow-prone into a smaller, well-understood operation you already trust. A matrix rotation becomes two simpler in-place transformations. A rectangle-overlap check becomes two 1D interval checks. A number too big for any built-in type becomes digit-by-digit arithmetic on an array. And almost every "obvious" numeric trick here has a genuine overflow trap lurking in it that a naive C++ implementation walks straight into.

In-place matrix transformations: decompose, don't derive

Rotate Image looks like it needs careful index arithmetic to map each cell to its rotated position — but it's actually two operations you already understand, composed: transpose the matrix (flip across the main diagonal), then reverse every row. Set Matrix Zeroes has the same flavor: rather than deriving a clever in-place zeroing scheme from scratch, it reuses the matrix's own first row and first column as marker storage, exactly the way you'd use any other O(1)-space scratch area. Spiral Matrix is the one case here that's genuinely a direct simulation — four shrinking boundaries (top, bottom, left, right), walked in order — but even there, the subtlety is a boundary-guard problem, not an algorithmic one.

The habit to build

In Spiral Matrix, the second half of each lap (walking the bottom row leftward, then the left column upward) needs an explicit guard — if (top <= bottom), if (left <= right) — or a matrix that's shrunk to a single remaining row or column gets some cells visited twice. This is the single most common bug in this problem, and it only shows up on non-square inputs, which is exactly why a correct-looking solution can still fail hidden tests.

1
2
3
4
5
6
7
8
9
original
transpose →
1
4
7
2
5
8
3
6
9
transposed
reverse rows →
7
4
1
8
5
2
9
6
3
rotated 90° clockwise
Rotate Image: transpose flips the matrix across its main diagonal, then reversing every row finishes the 90° clockwise rotation — two operations you already trust, composed, instead of deriving new rotated-index arithmetic from scratch.

Overflow safety: promote before the risky operation, never after

Pow(x, n), Reverse Integer, and Palindrome Number all share one discipline: the moment an operation might overflow a 32-bit int, promote to a wider type before doing that operation, not after it's already happened. Pow(x, n) negates its exponent — but n == INT_MIN has no positive int representation, so the exponent must be promoted to long long first. Reverse Integer accumulates its reversed digits in long long, checking against INT_MIN/INT_MAX only at the very end. Palindrome Number sidesteps the whole problem by only ever reversing half the digits — since the reversed half can never approach the range where overflow would even be possible.

Positional notation, generalized: base-26 and long multiplication

Excel Sheet Column Number is base-10 string-to-integer conversion wearing a disguise — base 26 instead of base 10, with a +1 offset per digit since there's no symbol for "zero" in spreadsheet column letters. Multiply Strings generalizes the same positional-arithmetic instinct in the other direction: instead of converting huge digit strings into a built-in integer type (which would overflow immediately), it performs grade-school long multiplication directly on a result array, exploiting the fact that multiplying digit i by digit j always contributes to fixed positions i+j and i+j+1 in the output — no manual digit alignment required.

Number theory at scale: sieve instead of per-number checks

Count Primes is the clearest lesson in this topic on why per-element correctness isn't enough — an algorithm's shape has to match the scale of its input. Checking each number below n for primality individually costs roughly O(n·√n), which is billions of operations once n reaches into the millions. The Sieve of Eratosthenes flips the question: instead of asking "is this number prime?" one at a time, mark every multiple of each prime as composite, starting from p*p (every smaller multiple already got marked by a smaller prime factor) — bringing the total cost down to O(n log log n), which is what actually makes the large-n case tractable.

Geometry as decomposed 1D checks

Rectangle Overlap turns a 2D shape question into two independent 1D interval-overlap checks — do the x-ranges overlap and do the y-ranges overlap — with strict inequality being exactly what excludes edge-touching and corner-touching from counting. Max Points on a Line takes the same "reduce to something exact" instinct further: instead of computing floating-point slopes (which accumulate rounding error and can wrongly split truly-collinear points into separate buckets), it represents each direction as a reduced, sign-canonicalized integer pair — dividing by the GCD of the deltas, then normalizing sign so a direction and its exact opposite always hash to the same bucket.

Common mistakes

  • Negating INT_MIN as a plain int — its magnitude has no positive int representation; promote to a wider type first, in Pow(x, n) and anywhere else a sign flip is involved.
  • Reversing digits directly in int — Reverse Integer's whole point is that the reversed value can exceed the 32-bit range mid-computation; accumulate in long long and check bounds only at the end.
  • Forgetting Spiral Matrix's second-half boundary guards — without top <= bottom / left <= right checks, single-row or single-column remainders get some cells visited twice.
  • Comparing floating-point slopes for exact collinearity — Max Points on a Line needs an exact integer representation (reduced, sign-canonicalized (dx, dy) pairs), not floating-point division, or truly collinear points can wrongly end up in different buckets.
  • Reaching for a per-number or per-element check when the problem's scale demands a batch technique — Count Primes' naive per-number trial division and Rotate Image's "derive the rotated index directly" both look reasonable until you notice a simpler, composed operation (a sieve; transpose-then-reverse) is both easier to get right and asymptotically faster.

Takeaways

  • A problem that looks like it needs new index arithmetic can often be decomposed into operations you already trust (transpose + reverse; two 1D interval checks).
  • Promote to a wider integer type before a risky operation (negation, digit reversal), never after — the overflow has already happened by the time you check.
  • Positional notation generalizes past base 10 — spreadsheet columns are base 26, and arbitrary-precision multiplication is just long multiplication done explicitly on a digit array.
  • When a problem's cost scales with magnitude rather than count, look for a batch technique (a sieve, an exact integer slope) instead of a per-element or floating-point one.

Try it: decompose, don't derive

Rotate Image — transpose, then reverse each row. Two operations you already trust, composed.

Live

Loading starter code…

Try it: promote before the risky operation

Pow(x, n) — binary exponentiation, and the INT_MIN negation trap that catches a naive implementation.

Live

Loading starter code…

Try it: exact geometry over floating point

Max Points on a Line — reduced, sign-canonicalized integer slopes instead of error-prone floating-point ones.

Live

Loading starter code…

Keep going

That's 3 of the 12 problems in this topic. Count Primes is worth doing next — it's the clearest demonstration of why an algorithm's shape has to match the scale of its input. See the full Math & Geometry set →

Checkpoint · Math & Geometry

5 questions · pass at 70%

Q01
Rotate Image rotates an n x n matrix 90 degrees clockwise by transposing it and then reversing each row, rather than computing each cell's rotated destination index directly. What's the main benefit of this approach?
WhyTranspose-then-reverse-rows is a composition of two operations you already trust individually (flipping across the diagonal, reversing a row) rather than deriving new rotated-index arithmetic from scratch. This is a recurring theme in this topic: break a problem that looks like it needs new geometric reasoning into pieces you've already solved before.
Q02
Pow(x, n) promotes n to a long long and negates that wider value, rather than negating n directly as an int, before handling a negative exponent. Why is this promotion necessary?
WhyA 32-bit signed int can represent -2^31 (INT_MIN) but not +2^31 -- the positive range tops out at 2^31 - 1. Negating INT_MIN as a plain int is undefined behavior for exactly this reason. Promoting n to long long BEFORE negating gives the negated value a valid representation, since long long's range comfortably covers 2^31. This is the same 'promote before the risky operation' discipline that shows up across this whole topic.
Q03
Reverse Integer accumulates its reversed digits in a long long and only converts back down to int (after checking the value fits) at the very end, rather than accumulating directly in int. What problem does this avoid?
WhyIf you build up the reversed value in a plain int, the moment the true reversed value exceeds INT_MAX or goes below INT_MIN, you've already triggered undefined behavior -- which defeats the point, since detecting that overflow and returning 0 is the whole task. Accumulating in long long first (which can hold any possible 32-bit reversal without overflowing) lets you safely check the bounds after the fact and only then narrow to int.
Q04
Count Primes' sieve starts marking multiples of each prime p at p*p rather than at 2*p. Why is starting at 2*p unnecessary?
WhyAny multiple of p that's smaller than p*p must have a prime factor smaller than p (since it equals p times something less than p, and that 'something less than p' must itself have a prime factor below p unless it's 1). That means it was already marked composite during an earlier, smaller prime's pass. Starting each prime's marking pass at p*p skips that already-done work without missing anything, which is part of what keeps the sieve at O(n log log n) instead of doing redundant marking.
Q05
Max Points on a Line represents each direction between two points as a reduced, sign-canonicalized integer pair (dx, dy) rather than as a floating-point slope (dy / dx). Why?
WhyFloating-point division is inexact -- two pairs of points that are mathematically on the exact same line can produce dy/dx values that differ in their least significant bits, causing them to hash into different buckets even though they should be grouped together. Representing the direction as an exactly-reduced (divided by GCD) and sign-canonicalized integer pair avoids any rounding error entirely, so truly collinear points always produce an identical key.

Finished Math & Geometry?

Pass the quiz to complete it automatically.