Software Engineer's Blog

Math and Geometry: Grid Work and Careful Arithmetic

Math and Geometry: Grid Work and Careful Arithmetic

The problems filed under Math and Geometry sort into two kinds of work. One is driving a matrix by careful index control — rotating values in place, reading them off in spiral order, zeroing rows and columns — without losing track of i and j. The other is doing arithmetic by hand — carry propagation, overflow, fast exponentiation — because the language’s + and * would either overflow silently or skip the very step the problem is testing. No single algorithm ties the eight together, so the work is telling which of the two threads you’re on and giving the boundaries the care the logic pretends it doesn’t need.

Matrix problems are index bookkeeping

Rotate Image, Spiral Matrix, and Set Matrix Zeroes all come down to walking or rearranging a grid under tight index control — Rotate and Set Zeroes mutate it in place, Spiral just reads it in order — without losing track of i and j.

  • Rotate Image turns a 90° rotation into two moves you can each reason about: transpose the matrix (swap m[i][j] with m[j][i]), then reverse each row. Composed, that’s a clockwise quarter-turn, done in place with no second grid.
  • Spiral Matrix is four boundaries — top, bottom, left, right — that you walk and then shrink inward, and the entire difficulty is stopping each edge at the right moment so you neither repeat a cell nor skip one.
  • Set Matrix Zeroes wants O(1)O(1) extra space, so instead of a separate “should this be zeroed” grid you use the matrix’s own first row and column as the marker flags — a nice trick that’s mostly about remembering to handle those two marker lines last.

The lesson these teach is unglamorous but real: draw the small case, index it by hand, and only then write the loop.

Simulating arithmetic the hard way

The numeric problems mostly ask you to rebuild an operation the language would happily do, precisely so you have to think about its edges.

  • Plus One and Multiply Strings are grade-school arithmetic on digit arrays — the whole game is carry propagation and lining up result[i + j] correctly. They exist because the “real” answer would overflow a 64-bit integer, so you work digit by digit like a bignum library does.
  • Pow(x, n) is the one with an actual algorithm: fast exponentiation. Since xn=(xn/2)2x^n = (x^{n/2})^2 when n is even and x(x(n1)/2)2x \cdot (x^{(n-1)/2})^2 when it’s odd, you halve the exponent each step and reach the answer in O(logn)O(\log n) multiplications instead of n — with a careful hand for negative exponents and for Integer.MIN_VALUE, whose magnitude has no positive int.
  • Happy Number looks like number theory but is secretly a cycle problem: repeatedly replace the number with the sum of the squares of its digits, and you either reach 1 or fall into a loop — which means Floyd’s fast-and-slow pointers detect it exactly as they do on a linked list.
  • Detect Squares is a small design problem: keep a count of every point you’ve seen in a hash map, and for a query point, look for the diagonal partners that would complete an axis-aligned square.

Overflow is the recurring villain

More than any other category, these problems are decided by the boundary you didn’t check. Reversing an integer can push it past Integer.MAX_VALUE; multiplying two mid-sized numbers overflows silently; Math.abs(Integer.MIN_VALUE) is still negative because there’s no positive counterpart. The habit that saves you is to ask, before writing the arithmetic, “what’s the largest this can get, and does it still fit?” — and to check for the overflow before performing the step that would cause it, not after, when the value has already wrapped. The reflex I’ve built is to widen to long at the first sign of a product or a reversal, or reach for Math.multiplyExact, which throws instead of wrapping — a silent overflow costs far more time to track down than the cast ever saves.

Where the tricks show up

Fast exponentiation isn’t confined to Pow: its modular cousin, computing xnmodmx^n \bmod m by the same halving, is the core of RSA and Diffie-Hellman, which raise huge numbers to huge powers without ever holding the full result. Matrix transposition and rotation are the primitive operations behind image filters and graphics transforms; digit-array arithmetic is the idea behind arbitrary-precision (BigInteger) libraries, which store word-sized limbs and switch to faster multiplication algorithms — Karatsuba, Toom–Cook — as the numbers grow.

Two threads and a boundary

Stripped down, the category is one sorting decision followed by one discipline. Decide whether a problem is grid-juggling or arithmetic-by-hand, then give its boundary the attention it doesn’t advertise: the last marker row in Set Matrix Zeroes, the edge that must stop one cell short in Spiral Matrix, the product that overflowed a step ago. An untested 3×3 worked out on paper catches more of these than any amount of rereading the loop — this is the corner of the set that punishes hurry more than it rewards cleverness.

References