21. Math and Geometry#
Theory#
Math and geometry problems in interviews rarely require calculus. They combine number theory (GCD, modular arithmetic, exponentiation), 2D coordinate reasoning (slopes, distances, matrix traversal), and occasionally vector operations (dot/cross product for orientation and area). The pattern is: translate the problem into a mathematical invariant, then implement it carefully while avoiding floating-point pitfalls.
See also: Bit Manipulation (XOR, bit tricks), Binary Search (Sqrt(x) via search on answer), Fast and Slow Pointers (Happy Number cycle detection).
Vectors#
A 2D vector is an ordered pair (x, y) representing displacement from the origin. In code, points and vectors are often the same type; context distinguishes position vs direction.
| Operation | Formula | Use in DSA |
|---|---|---|
| Add | (x₁, y₁) + (x₂, y₂) = (x₁+x₂, y₁+y₂) |
Translate points; sum edge vectors |
| Scalar multiply | k · (x, y) = (kx, ky) |
Scale direction |
| Magnitude | \|v\| = √(x² + y²) |
Distance from origin |
| Unit vector | v / \|v\| |
Normalize slope (avoid floats — use GCD instead) |
Dot product: a · b = x₁x₂ + y₁y₂
a · b = 0→ vectors are perpendicular- Sign tells whether angle is acute or obtuse
- Projects one vector onto another:
proj_a(b) = (a·b / |a|²) · a
Cross product (2D): treat vectors as 3D with z = 0. The scalar result is the signed z-component:
a × b = x₁y₂ − x₂y₁
Sign of a × b |
Meaning |
|---|---|
> 0 |
b is counter-clockwise from a |
< 0 |
b is clockwise from a |
= 0 |
Collinear (same or opposite direction) |
Use cross product for orientation tests (convex hull, "which side of a line?") and area: triangle area = |a × b| / 2.
GCD and LCM#
Greatest Common Divisor (GCD) — largest integer dividing both a and b.
Euclidean algorithm:
Extended GCD finds x, y such that ax + by = gcd(a, b) — used in modular inverse problems.
Least Common Multiple: lcm(a, b) = |a · b| / gcd(a, b)
Why GCD matters in geometry:
- Represent slope as reduced fraction
(dy, dx)withgcd(|dy|, |dx|) = 1— avoids floating-point equality bugs in "points on a line" problems. - Normalize direction vectors so
(dy, dx)and(-dy, -dx)map to the same key.
Modular Arithmetic#
When results can overflow or you need remainders, work in mod m.
Core properties (for integers a, b and mod m):
(a + b) mod m = ((a mod m) + (b mod m)) mod m(a · b) mod m = ((a mod m) · (b mod m)) mod m(a − b) mod m = ((a mod m) − (b mod m) + m) mod m← handle negatives
Modular exponentiation (binary exponentiation / exponentiation by squaring):
def mod_pow(base: int, exp: int, mod: int) -> int:
result, b = 1, base % mod
while exp:
if exp & 1:
result = (result * b) % mod
b = (b * b) % mod
exp >>= 1
return result
Time: O(log exp). Used in Pow(x, n), Super Pow, and cryptography-style problems.
Tip: For x^n where n is negative, compute x^|n| then take reciprocal: 1 / x^n.
Coordinate Geometry Basics#
| Concept | Formula / Rule |
|---|---|
| Distance | √((x₂−x₁)² + (y₂−y₁)²) — compare squared distance to avoid sqrt |
| Slope | (y₂−y₁) / (x₂−x₁) — use reduced (dy, dx) pair instead of float |
| Collinearity | Cross product (p−a) × (q−a) == 0 for points p, q, a |
| Line through origin | Points (x, y) with y/x = k share slope k |
| Rectangle overlap | Intervals overlap on both axes ⟺ rectangles intersect |
| Matrix as grid | (row, col) with directions (dr, dc) — map compass to deltas |
Direction vectors for matrix traversal:
DIRS_4 = [(0, 1), (1, 0), (0, -1), (-1, 0)] # right, down, left, up
DIRS_8 = DIRS_4 + [(1, 1), (1, -1), (-1, -1), (-1, 1)]
In-place matrix transforms: rotate 90° clockwise = transpose then reverse each row; reflect across anti-diagonal = swap matrix[i][j] with matrix[j][i] then reverse rows.
Problems at a glance#
| LC | Problem | |
|---|---|---|
| 48 | 1. Rotate Image | ↗ |
| 73 | 2. Set Matrix Zeroes | ↗ |
| 54 | 3. Spiral Matrix | ↗ |
| 50 | 4. Pow(x, n) | ↗ |
| 149 | 5. Max Points on a Line | ↗ |
| 1232 | 6. Check If It Is a Straight Line | ↗ |
| 372 | 7. Super Pow | ↗ |
| 367 | 8. Valid Perfect Square | ↗ |
| 836 | 9. Rectangle Overlap | ↗ |
| 2013 | 10. Detect Squares | ↗ |
Problems#
1. Rotate Image (Leetcode:48)#
Problem Statement
You are given an n x n 2D matrix representing an image, rotate the image by 90 degrees clockwise.
You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.
Example 1:
Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output: [[7,4,1],[8,5,2],[9,6,3]]
Example 2:
Input: matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
Output: [[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]
Constraints:
n == matrix.length == matrix[i].length
1 <= n <= 20
-1000 <= matrix[i][j] <= 1000
Code and Explanation
- 90° clockwise equals transpose then reverse each row.
- Transpose reflects across the main diagonal: element at
(i, j)moves to(j, i). - Reversing rows completes the clockwise rotation in O(1) extra space.
Time: O(n²) | Space: O(1)
- Process concentric layers from outside in.
- Each group of four cells rotates as a 4-cycle: top → left → bottom → right.
- Direct in-place rotation without explicit transpose — same complexity, more index arithmetic.
Time: O(n²) | Space: O(1)
2. Set Matrix Zeroes (Leetcode:73)#
Problem Statement
Given an m x n integer matrix matrix, if an element is 0, set its entire row and column to 0s.
You must do it in place.
Example 1:
Input: matrix = [[1,1,1],[1,0,1],[1,1,1]]
Output: [[1,0,1],[0,0,0],[1,0,1]]
Example 2:
Input: matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
Output: [[0,0,0,0],[0,4,5,0],[0,3,1,0]]
Constraints:
m == matrix.length
n == matrix[0].length
1 <= m, n <= 200
-2^31 <= matrix[i][j] <= 2^31 - 1
Follow up:
A straightforward solution using O(mn) space is probably a bad idea.
A simple improvement uses O(m + n) space, but still not the best.
Could you devise a constant space solution?
Code and Explanation
- Record whether row 0 or column 0 originally contained a zero (they need special handling).
- For each zero at
(i, j), markmatrix[i][0]andmatrix[0][j]— reusing first row/column as bit flags. - Second pass zeroes interior cells using markers, then fix row 0 and column 0 last.
Time: O(m · n) | Space: O(1)
- Collect all row and column indices that contain at least one zero.
- Zero entire rows and columns in separate passes.
- Simpler to reason about, but uses O(m + n) extra space.
Time: O(m · n) | Space: O(m + n)
3. Spiral Matrix (Leetcode:54)#
Problem Statement
Given an m x n matrix, return all elements of the matrix in spiral order.
Example 1:
Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output: [1,2,3,6,9,8,7,4,5]
Example 2:
Input: matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
Output: [1,2,3,4,8,12,11,10,9,5,6,7]
Constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 10
-100 <= matrix[i][j] <= 100
Code and Explanation
- Maintain four boundaries:
top,bottom,left,right. - Traverse right → down → left → up, then shrink the corresponding boundary.
- Guard the left/up passes with
if top <= bottom/if left <= rightto avoid duplicates on non-square matrices.
Time: O(m · n) | Space: O(1) excluding output
- Walk using a direction index that rotates on hitting a wall or visited cell.
- Direction vectors encode coordinate geometry:
(dr, dc)pairs. - Easier to extend to similar spiral-fill problems; uses O(m · n) visited space.
Time: O(m · n) | Space: O(m · n)
4. Pow(x, n) (Leetcode:50)#
Problem Statement
Implement pow(x, n), which calculates x raised to the power n (i.e., x^n).
Example 1:
Input: x = 2.00000, n = 10
Output: 1024.00000
Example 2:
Input: x = 2.10000, n = 3
Output: 9.26100
Example 3:
Input: x = 2.00000, n = -2
Output: 0.25000
Explanation: 2⁻² = 1/2² = 1/4 = 0.25
Constraints:
-100.0 < x < 100.0
-2^31 <= n <= 2^31 - 1
nis an integer.
Eitherxis not zero orn > 0.
-10^4 <= x^n <= 10^4
Code and Explanation
- Handle negative exponent: compute
x^|n|then invert (1/xeach step). - Exponentiation by squaring: if
nis odd, multiply result by currentx; then squarexand halven. - Each bit of
nprocessed once → O(log n) multiplications instead of O(n).
Time: O(log n) | Space: O(1)
- Base case:
x^0 = 1. - Even
n:x^n = (x^(n/2))²— halve the problem. - Odd
n: peel one factor and recurse. Same O(log n) depth, more stack frames.
Time: O(log n) | Space: O(log n) recursion stack
5. Max Points on a Line (Leetcode:149)#
Problem Statement
Given an array of points where points[i] = [xᵢ, yᵢ] represents a point on the X-Y plane, return the maximum number of points that lie on the same straight line.
Example 1:
Input: points = [[1,1],[2,2],[3,3]]
Output: 3
Example 2:
Input: points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
Output: 4
Constraints:
1 <= points.length <= 300
points[i].length == 2
-10^4 <= xᵢ, yᵢ <= 10^4
All thepointsare unique.
Code and Explanation
- Fix an anchor point
points[i]and count how many other points share each slope. - Represent slope as reduced fraction
(dx, dy)via GCD — avoids float comparison errors. - Canonicalize direction (flip signs so
dx > 0) so(1,2)and(-1,-2)match. - Track duplicate anchor coordinates separately (
samecounter).
Time: O(n²) | Space: O(n)
- Pick two points to define a line; test every third point with cross product = 0.
- Integer arithmetic only — no slope division.
- O(n³) but clear geometrically; acceptable for small constraints or as interview warm-up before optimizing to O(n²).
Time: O(n³) | Space: O(1)
6. Check If It Is a Straight Line (Leetcode:1232)#
Problem Statement
You are given an array coordinates, coordinates[i] = [x, y], where [x, y] represents the coordinate of a point. Check if these points make a straight line in the XY plane.
Example 1:
Input: coordinates = [[1,2],[2,3],[3,4],[4,5],[5,6],[6,7]]
Output: true
Example 2:
Input: coordinates = [[1,1],[2,2],[3,4],[4,5],[5,6],[7,7]]
Output: false
Constraints:
2 <= coordinates.length <= 1000
coordinates[i].length == 2
-10^4 <= xᵢ, yᵢ <= 10^4
coordinatescontains no duplicate point.
Code and Explanation
- Use first two points as reference direction vector
(x1−x0, y1−y0). - Every other point must satisfy cross product = 0 with the reference — integer safe, no division.
- Handles vertical lines naturally (no undefined slope).
Time: O(n) | Space: O(1)
- Equivalent to comparing
(y2−y0)/(x2−x0)with(y1−y0)/(x1−x0)via cross-multiplication. - Same cross-product logic, written as slope equality without floating point.
Time: O(n) | Space: O(1)
7. Super Pow (Leetcode:372)#
Problem Statement
Your task is to calculate aᵇ mod 1337 where a is a positive integer and b is an extremely large positive integer given in the form of an array.
Example 1:
Input: a = 2, b = [3]
Output: 8
Example 2:
Input: a = 2, b = [1,0]
Output: 1024
Example 3:
Input: a = 1, b = [4,3,3,8,5,2]
Output: 1
Constraints:
1 <= a <= 2^31 - 1
1 <= b.length <= 2000
0 <= b[i] <= 9
bdoes not contain leading zeros.
Code and Explanation
- Exponent
bis too large to store — process digit by digit using the identitya^(10·q + d) = (a^q)^10 · a^d. - Maintain running result; for each digit
d, square result 10 times (viapow_mod(result, 10)) then multiply bya^d. - All arithmetic mod 1337 prevents overflow.
Time: O(k · log d · log MOD) where k = len(b) | Space: O(1)
- Recursively compute power for all but the last digit, then combine:
(prev^10) · a^last_digit. - Same mathematical decomposition as the iterative version; mutates
bviapop().
Time: O(k · log 10 · log MOD) | Space: O(k) recursion depth
8. Valid Perfect Square (Leetcode:367)#
Problem Statement
Given a positive integer num, write a function which returns True if num is a perfect square else False.
Follow up: Do not use any built-in library function such as sqrt.
Example 1:
Input: num = 16
Output: true
Example 2:
Input: num = 14
Output: false
Constraints:
1 <= num <= 2^31 - 1
Code and Explanation
- Newton's method for √num: iterate
x ← (x + num/x) / 2until convergence. - Integer division keeps everything in integer arithmetic — no floating point.
- Check
x * x == numat the end; classic math approach distinct from binary search (see Binary Search doc for Sqrt(x)).
Time: O(log num) | Space: O(1)
- Perfect squares are sums of first
kodd numbers: 1 = 1, 4 = 1+3, 9 = 1+3+5, … - Subtract successive odd integers; if we hit exactly 0,
numis a perfect square. - O(√num) but elegant number-theory insight.
Time: O(√num) | Space: O(1)
9. Rectangle Overlap (Leetcode:836)#
Problem Statement
An axis-aligned rectangle is represented as its bottom-left corner (x1, y1) and top-right corner (x2, y2).
Given two axis-aligned rectangles rec1 and rec2, return true if they overlap.
Example 1:
Input: rec1 = [0,0,2,2], rec2 = [1,1,3,3]
Output: true
Example 2:
Input: rec1 = [0,0,1,1], rec2 = [1,0,2,1]
Output: false
Example 3:
Input: rec1 = [0,0,1,1], rec2 = [2,2,3,3]
Output: false
Constraints:
rec1.length == 4
rec2.length == 4
-10^9 <= x1, y1, x2, y2 <= 10^9
x2 >= x1andy2 >= y1for both rectangles.
Code and Explanation
- Two axis-aligned rectangles overlap ⟺ their x-intervals and y-intervals both overlap.
rec = [x1, y1, x2, y2]— x-range is[x1, x2), y-range is[y1, y2)(touching edges = no overlap per problem).- Check separation on either axis; if neither separated, they overlap.
Time: O(1) | Space: O(1)
- Intersection width =
min(right edges) − max(left edges); same for height. - Positive width and height means positive-area overlap.
- Equivalent logic, often easier to extend to intersection area problems.
Time: O(1) | Space: O(1)
10. Detect Squares (Leetcode:2013)#
Problem Statement
You are given a stream of points on the X-Y plane. Design an algorithm that:
- Adds new points from the stream into a data structure. Duplicate points are allowed to be added more than once.
- Counts the number of ways to form axis-aligned squares such that the point
(x, y)belongs to the square and has an edge parallel to the X-axis.
Implement the DetectSquares class:
DetectSquares()Initializes the object with an empty data structure.void add(int[] point)Adds a new pointpoint = [x, y]to the data structure.int count(int[] point)Counts the number of ways to form axis-aligned squarespbelongs to.
Example 1:
Input:
["DetectSquares", "add", "add", "add", "count", "count", "add", "count"]
[[], [[3, 10]], [[11, 2]], [[3, 2]], [[11, 10]], [[14, 8]], [[11, 2]], [[11, 10]]]
Output:[null, null, null, null, 1, 0, null, 2]
Constraints:
point.length == 2
0 <= x, y <= 1000
At most3000calls toaddandcount.
Code and Explanation
- Fix query point
(x, y)as one corner; iterate all stored points(px, py)as potential diagonal corner. - Skip if same row/column (not diagonal) or if
|px−x| ≠ |py−y|(not a square diagonal). - The other two corners are
(x, py)and(px, y)— multiply point counts for all four corners (handles duplicates via frequency map).
Time: O(n) per count, O(1) per add | Space: O(n) points stored
- Points on the same diagonal of a square with
(x, y)share the same midpoint — filter byx + ysum (or difference). - Prunes search space when many points exist; same corner-counting logic once diagonal partner found.
- Useful when
countis called frequently on large point sets.
Time: O(k) per count where k = points sharing diagonal sum | Space: O(n)
Skipped (Covered Elsewhere)#
| Problem | Reason |
|---|---|
| Happy Number (LC 202) | Primary pattern is Fast and Slow Pointers — see Pattern 02 |
| Sqrt(x) (LC 69) | Primary pattern is Binary Search on Answer — see Pattern 09 |