Hi👋SpeedAlgo • Deliberate Practice & Cognitive Ergonomics for Software Engineers

An interactive algorithm mastery and technical interview preparation platform published by Hi👋WebEnterprise. Built for senior and staff software engineers preparing for rigorous coding screens at top tech companies (FAANG/MAMAA).

13 Core Algorithmic Patterns & 225 Practice Problems

  • 1. Two Pointers (16 Paradigms, 43 Problems): Opposite ends, sorted pair sums, palindrome verification, trapping rain water, 3Sum, container with most water — includes the Sliding Window and Fast & Slow Pointers paradigms (contiguous subarray invariants, longest substrings, Floyd's cycle detection, linked list middle).
  • 2. Binary Search (9 Paradigms, 14 Problems): Monotonic predicate partitioning (feasible(x)), boundary search, rotated sorted arrays, square roots, minimum ship capacity, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 11 Problems): Counting set bits, XOR cancellation, bit reversal, bitmask pairing, maximum XOR with a bitwise trie.
  • 4. Math & Geometry (8 Paradigms, 14 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (15 Paradigms, 24 Problems): Path sums, lowest common ancestor, tree diameter, validating BSTs, tree DP (House Robber III, Binary Tree Cameras).
  • 6. Tree/Graph Breadth-First Search (5 Paradigms, 12 Problems): Level-order traversals, shortest path in unweighted graphs, zig-zag traversals, rotting oranges, word ladders.
  • 7. Graphs (12 Paradigms, 22 Problems): Topological sort, cycle detection, Dijkstra's algorithm, bipartite graph validation, network delay.
  • 8. Backtracking (6 Paradigms, 14 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens, Sudoku solver.
  • 9. Dynamic Programming (13 Paradigms, 28 Problems): Memoization vs tabulation, 0/1 knapsack, unbounded knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (9 Paradigms, 11 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (7 Paradigms, 17 Problems): Trie (prefix tree), Union-Find (Disjoint Set Union), LRU Cache, LFU Cache, range-sum queries with updates.
  • 12. Stack (5 Paradigms, 9 Problems): Next greater element, largest rectangle in histogram, remove k digits, decode string, min stack.
  • 13. Intervals & Greedy (2 Paradigms, 6 Problems): Merge intervals, interval scheduling, meeting rooms by sweep line, jump game.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Read the pattern's mental model, loop invariant and Big-O proof, compare the pattern's template with the problem's solution side by side, and use the step-by-step debugger. The solution can also be shown in C#, Java, TypeScript, C++, Go or Rust for almost every problem.
  2. Stage 2 (Active Recall): Rebuild the solution from memory in a code editor, with an invariant checklist and optional progressive hints, and check it against a judged test suite.
  3. Stage 3 (AI Interview Coach, coming soon): A mock-interview stage still in development; for now, students go straight from Stage 2 to Stage 4.
  4. Stage 4 (Solve on Your Own): Solve a new problem on your own against a 15-minute timer; your code is graded against a test suite. Python and TypeScript run in your browser and C# runs on our server (design problems grade in Python and TypeScript).

Equipped with a spaced-repetition review hub on a fixed 7-step schedule (1 day up to 90 days), a two-pane Studio workspace, and study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Coins: New accounts get 40 free coins once, the daily claim adds +20 coins once a day, and inviting a friend earns you +25 coins when they complete their first practice step. These are the only ways to earn coins.
  • AI Coach: Each AI coach question costs 1-5 coins, priced by the server according to its size.
  • BYOK (Bring Your Own Key): AI coaching is free with your own Google Gemini, OpenAI or OpenRouter API key (BYOK).
  • Extras: Coins also unlock extras for 24 hours: a Recall hint level (1 coin), a Solve solution reveal (2), a LeetCode problem card's solutions (1) and a pattern's extra canonical problems (1).
  • Payments & Refunds: Nothing on the site is sold for money: coins can only be earned, never bought. There are no subscriptions or charges, so there is nothing to refund.
  • Platform Operator: Hi👋WebEnterprise. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

Arena
238Items
Theory Context•Math & Geometry
HardLC 149

Max Points on a Line (LeetCode 149)

Target Frequency:MetaAppleAmazon

You're handed a list of 2D points, each entry points[i] = [xi, yi] marking a spot on the X-Y plane. Work out the size of the largest subset of those points that all sit on one common straight line.

Worked Examples

Example 1
Input:points = [[1,1],[2,2],[3,3]]
Output:3
(1, 1)(2, 2)(3, 3)
Explanation: All three points sit on the diagonal line y = x, so the whole set is collinear.
Example 2
Input:points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
Output:4
(1, 1)(3, 2)(5, 3)(4, 1)(2, 3)(1, 4)
Explanation: The four points (4,1), (3,2), (2,3), and (1,4) all satisfy x + y = 5, so they share one straight line -- the largest collinear group in this set.

⚖️Formal Constraints & Bounds

  • 1 <= points.length <= 300

  • points[i].length == 2

  • -104 <= xi, yi <= 104

  • All the points are unique.

Deep-Dive & Conceptual Insights

Core Insight

Floating-point division dy/dx suffers from precision issues. Instead, reduce (dy, dx) by their greatest common divisor (GCD) and store the coprime pair (dy // g, dx // g) as hash map keys.

Real-World Scenario & Production Applications

Computer vision Hough transforms, radar trajectory line detection, geospatial linear feature recognition.

Step-by-Step Execution Trace Table

Anchor PointTarget PointSlope Delta (dx, dy)Coprime Reduction (dy // g, dx // g)Slopes Map for AnchorLocal Collinear Max
(1, 1)(2, 2)dx = 1, dy = 1gcd=1 \implies (1, 1){(1, 1): 1}2 points
(1, 1)(3, 3)dx = 2, dy = 2gcd=2 \implies (1, 1){(1, 1): 2}3 points
(1, 1)(1, 4)dx = 0, dy = 3Vertical line →\to→ (1, 0){(1, 1): 2, (1, 0): 1}3 points
Worked on Paper

The Math, Step by Step

1. The key that names a direction

Fix one point, the anchor (x1,y1)(x_1, y_1)(x1​,y1​). Any other point (x2,y2)(x_2, y_2)(x2​,y2​) lies in some direction from it. Write that direction as the step from the anchor to the point:

dx=x2−x1dy=y2−y1dx = x_2 - x_1 \qquad dy = y_2 - y_1dx=x2​−x1​dy=y2​−y1​

Two points lie on the same line through the anchor when their steps point the same way or exactly opposite ways. The steps (2,1)(2, 1)(2,1) and (4,2)(4, 2)(4,2) and (−2,−1)(-2, -1)(−2,−1) all describe the same line. The code needs one canonical key for each line: a single value that every point of that line produces, and no point of another line produces.

2. Building the key for one pair

The code builds the key in two steps.

First it divides both parts by g=gcd⁡(dx,dy)g = \gcd(dx, dy)g=gcd(dx,dy), the greatest common divisor. Python's math.gcd always returns a non-negative number, and g>0g > 0g>0 here because all points are different. After the division, the two parts have no common factor left. So (4,2)(4, 2)(4,2) and (2,1)(2, 1)(2,1) both become (2,1)(2, 1)(2,1). The key stores dydydy first, as (dy // g, dx // g). The division is exact, because ggg divides both parts.

Then it fixes the sign, because (2,1)(2, 1)(2,1) and (−2,−1)(-2, -1)(−2,−1) are still different pairs. The rule makes the first part positive, or, when the first part is 0, makes the second part positive:

Key (dy // g, dx // g) before the sign fixKind of lineKey after the sign fix
first part >0> 0>0rising or fallingunchanged
first part <0< 0<0rising or fallingboth parts negated
first part =0= 0=0, second part >0> 0>0horizontalunchanged, (0,1)(0, 1)(0,1)
first part =0= 0=0, second part <0< 0<0horizontalnegated to (0,1)(0, 1)(0,1)

A vertical line has dx=0dx = 0dx=0, so g=∣dy∣g = |dy|g=∣dy∣ and the key is (1,0)(1, 0)(1,0) or (−1,0)(-1, 0)(−1,0). The sign fix makes it (1,0)(1, 0)(1,0). No division by zero ever happens.

3. Why equal keys mean one line

Two points with the same key have steps from the anchor that are whole multiples of the same reduced pair. So both lie on the one line through the anchor in that direction. Two points on different lines through the anchor have directions that are not multiples of each other. After dividing by the gcd and fixing the sign, their keys differ. A line through the anchor is fully fixed by one point and its direction, so counting equal keys counts the points on each line.

For each anchor, slopes[key] counts the other points on the line with that key. The line also holds the anchor itself, so it has slopes[key] + 1 points.

4. Why later points are enough, and the small inputs

The inner loop only looks at points with index j>ij > ij>i. That is enough. Take the line with the most points, and let iii be the smallest index among them. When the anchor is point iii, all the other points of that line have larger indices, so they are all counted.

With one or two points, every point is on one line, so the code returns len(points) at once. The loops would return 0 for a single point, because they never run a pair.

5. Example 2 by hand

points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]].

012345

The picture shows the six points, labelled by index. Points 1, 3, 4 and 5 are (3,2)(3, 2)(3,2), (4,1)(4, 1)(4,1), (2,3)(2, 3)(2,3) and (1,4)(1, 4)(1,4). They lie on the line x+y=5x + y = 5x+y=5, which falls by 1 for every step of 1 to the right.

The smallest index on that line is 1, so the anchor (3,2)(3, 2)(3,2) finds it:

jPointdxdxdxdydydyggg(dy // g, dx // g)Key after the sign fixslopes[key]
2(5,3)(5, 3)(5,3)211(1,2)(1, 2)(1,2)(1,2)(1, 2)(1,2)1
3(4,1)(4, 1)(4,1)1−1-1−11(−1,1)(-1, 1)(−1,1)(1,−1)(1, -1)(1,−1)1
4(2,3)(2, 3)(2,3)−1-1−111(1,−1)(1, -1)(1,−1)(1,−1)(1, -1)(1,−1)2
5(1,4)(1, 4)(1,4)−2-2−222(1,−1)(1, -1)(1,−1)(1,−1)(1, -1)(1,−1)3

Row j = 3 shows why the sign fix is needed. Before it, (4,1)(4, 1)(4,1) gives (−1,1)(-1, 1)(−1,1) and (2,3)(2, 3)(2,3) gives (1,−1)(1, -1)(1,−1). Both points are on the same line, but their pairs differ. After the fix, both keys are (1,−1)(1, -1)(1,−1). Row j = 5 shows why the gcd is needed. Its step (−2,2)(-2, 2)(−2,2) is twice the step of row j = 4, and dividing by g=2g = 2g=2 gives the same key.

After row j = 5, the key (1,−1)(1, -1)(1,−1) has count 3, so this line holds 3+1=43 + 1 = 43+1=4 points. No anchor finds a larger count, so the code returns 4, the expected output.

6. Example 1 by hand

points = [[1,1],[2,2],[3,3]]. With the anchor (1,1)(1, 1)(1,1), the point (2,2)(2, 2)(2,2) has step (1,1)(1, 1)(1,1) and key (1,1)(1, 1)(1,1). The point (3,3)(3, 3)(3,3) has step (2,2)(2, 2)(2,2). Its gcd is 2, so its key is also (1,1)(1, 1)(1,1). The count for (1,1)(1, 1)(1,1) reaches 2, so the line holds 2+1=32 + 1 = 32+1=3 points. The code returns 3, the expected output.

7. From the math to the code
MathIn maxPoints
the step from the anchordx, dy = x2 - x1, y2 - y1
g=gcd⁡(dx,dy)g = \gcd(dx, dy)g=gcd(dx,dy)g = math.gcd(dx, dy)
the reduced pair, dydydy firstslope = (dy // g, dx // g)
the sign fixif slope[0] < 0 or (slope[0] == 0 and slope[1] < 0): then negate both parts
points on this line, plus the anchorslopes[slope] += 1 and slopes[slope] + 1
the largest line over all anchorsmax_pts = max(max_pts, slopes[slope] + 1)

The two loops look at every pair once, and each key takes one gcd. Under LeetCode's limits every coordinate difference is at most 2⋅1042 \cdot 10^42⋅104, so one gcd takes a bounded number of steps. So the code takes O(n2)O(n^2)O(n2) time. The map for one anchor holds at most n−1n - 1n−1 keys, so it uses O(n)O(n)O(n) space.

Code Shape
Archetype Code Shape
Python
1if len(points) <= 2:
2 return len(points)
3max_pts = 0
4for i in range(len(points)):
5 slopes = defaultdict(int)
6 x1, y1 = points[i]
7 for j in range(i + 1, len(points)):
8 dx, dy = x2 - x1, y2 - y1
9 g = math.gcd(dx, dy)
10 slope = (dy // g, dx // g), with one fixed sign
11 slopes[slope] += 1
12 max_pts = max(max_pts, slopes[slope] + 1)
13return max_pts

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

Grouping points by slope sounds like it should just be dy / dx in a hash map — until you remember floats lie.

📏 The Analogy: A Surveyor Who Never Trusts Decimals

Imagine a surveyor comparing the steepness of different paths. Two paths are "the same direction" only if their rise-over-run ratios are exactly equal — but a surveyor who measures steepness as a decimal (0.3333...) risks two genuinely-identical directions coming out as 0.33333 and 0.33334 due to rounding, and missing that they're the same line entirely. A careful surveyor never divides at all. Instead, they write the ratio as a fraction and simplify it down to its smallest possible whole-number form — 9/3 and 6/2 both simplify to 3/1, and now they're exactly the same key, no rounding involved.

🔑 The Key Idea in the Code

math.gcd(dx, dy) finds the largest whole number that divides both the rise and the run evenly. Dividing both by it collapses every direction to one, canonical, integer-pair key — (3, 1) and never 0.333.... Two points genuinely on the same line through the anchor will always reduce to the identical pair, so the hash map lookup is 100% reliable instead of "usually right."

  • Floating point slope division precision error: Computing slope as dy / dx uses IEEE 754 floating-point numbers, which suffer precision drift on steep slopes. Normalize the fraction (dy // g, dx // g) using the greatest common divisor (GCD).

  • Vertical line division by zero: When two points share the same x-coordinate (dx=0dx = 0dx=0), division by zero crashes. Normalize vertical slopes to a fixed sentinel like (1, 0).

  • Duplicate points at identical coordinates: When points share the exact same (x,y)(x, y)(x,y) coordinates, slope is undefined; track duplicate point counts separately and add to the maximum collinear line.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Maximum points lying on the same straight line, geometry 2D coordinate plane, line slope collisions.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Invariant: Two lines passing through the same anchor point i with identical reduced slopes (dy/gcd, dx/gcd) represent the exact same line.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • The card's trap, with the blueprint's rule: flip slope when slope[0] < 0 or (slope[0] == 0 and slope[1] < 0), so dy ends up positive (or dy == 0 with dx positive).

  • Vertical and horizontal lines need no special case: gcd(0, dy) is abs(dy), so a vertical line becomes (1, 0) after the sign fix, and a horizontal one becomes (0, 1).

  • Count the anchor too: the line through points[i] holds slopes[slope] + 1 points; without the + 1 every answer is one short.

The 60-Second Interview Pitch

Say this out loud before you type a single line

I'd use a Canonical Key. A line through two points is fixed by one anchor point and a direction, so for each anchor points[i] I fill a fresh map slopes with the direction to every later point points[j]. I write that direction as the reduced integer pair (dy // g, dx // g) with g = gcd(dx, dy), so directions such as (2, 4) and (1, 2) get the same key. Two points lie on the same line through the anchor exactly when their pairs match, and integers compare exactly, unlike rounded float slopes. The trap is the sign: (1, -2) and (-1, 2) are the same direction, so I flip the pair whenever dy is negative, or dy is zero and dx is negative; otherwise one line is counted as two. The best line through the anchor has slopes[slope] + 1 points, counting the anchor itself. That's O(N²) time and O(N) space.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(N^2)

Look at the execution steps: For each point i (N choices), computes normalized slope (dy, dx) via GCD with all other N - 1 points j. Hash map tracks slope frequencies. Max slope count gives max collinear points through point i. Total N * (N - 1) slope calculations.

SPACE COMPLEXITY

O(N)

Look at memory allocations: Call stack uses O(1) Iterative. Hash map storing at most N - 1 reduced slope pairs per anchor point.

Formal Recurrence Relation

T(N) = ∑_{i=1}^N (N - i) = O(N^2)

Derivation Progression

Anchor Point Loop

N anchor points

Fixes point i as origin.

Normalized Slope Computation

g = gcd(dx, dy), (dy // g, dx // g)

Reduces the slope with Euclid's algorithm. Differences are at most 2 * 10^4, so one gcd takes at most 20 remainder steps (the worst pair is 17711 and 10946): a constant under these limits, so each pair costs O(1). (With unbounded coordinates C, the total would be O(N^2 log C).)

Slope Frequency Tally

slopes[(dy // g, dx // g)] += 1

Tally collinear lines through anchor point in O(1) map operation.

Variable Definitions

NNN

Total number of 2D points in the input array

Memory Architecture & Bounds

🟣 Call Stack

O(1) Iterative

🔵 Auxiliary Heap

O(N) Hash map of reduced slope fractions

🟢 Output Space

O(1) Max points integer

Boundary Best / Worst Cases

Best Case

O(1)O(1)O(1) for N <= 2.

Average Case

O(N2)O(N^2)O(N2).

Worst Case

O(N2)O(N^2)O(N2) general case.

Recurrence Tree Topology

Recurrence Tree Topology
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Key phrasing: the largest count of points sharing one straight line. Geometry trigger: slope collinearity. Points p1,p2,p3p_1, p_2, p_3p1​,p2​,p3​ are collinear if slope(p1,p2)==slope(p1,p3)\text{slope}(p_1, p_2) == \text{slope}(p_1, p_3)slope(p1​,p2​)==slope(p1​,p3​). The fatal junior trap is computing float(dy) / dx: floating-point division introduces IEEE-754 precision drift and rounding errors, causing identical slopes to hash to different buckets. A Senior SWE immediately implements Coprime GCD Slope Normalization: represent the slope as a canonical coprime integer pair (Δygcd⁡(Δx,Δy),Δxgcd⁡(Δx,Δy))(\frac{\Delta y}{\gcd(\Delta x, \Delta y)}, \frac{\Delta x}{\gcd(\Delta x, \Delta y)})(gcd(Δx,Δy)Δy​,gcd(Δx,Δy)Δx​).

CONSTRAINTS & BOUNDS

1≤points.length≤3001 \le points.length \le 3001≤points.length≤300. With N=300N=300N=300, an O(N2)O(N^2)O(N2) pairwise slope aggregation using a local hash map takes 3002=9×104300^2 = 9 \times 10^43002=9×104 pair checks.

FAANG PRODUCTION TRAPS & EDGE CASES

Edge case: N≤2N \le 2N≤2 immediately returns NNN. At scale, memory stays small because slopes is rebuilt for each anchor: it never holds more than N−1N - 1N−1 keys, although O(N2)O(N^2)O(N2) pairs are examined in total.

Theory Context•Math & Geometry
HardLC 149

Max Points on a Line (LeetCode 149)

Target Frequency:MetaAppleAmazon

You're handed a list of 2D points, each entry points[i] = [xi, yi] marking a spot on the X-Y plane. Work out the size of the largest subset of those points that all sit on one common straight line.

Worked Examples

Example 1
Input:points = [[1,1],[2,2],[3,3]]
Output:3
(1, 1)(2, 2)(3, 3)
Explanation: All three points sit on the diagonal line y = x, so the whole set is collinear.
Example 2
Input:points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
Output:4
(1, 1)(3, 2)(5, 3)(4, 1)(2, 3)(1, 4)
Explanation: The four points (4,1), (3,2), (2,3), and (1,4) all satisfy x + y = 5, so they share one straight line -- the largest collinear group in this set.

⚖️Formal Constraints & Bounds

  • 1 <= points.length <= 300

  • points[i].length == 2

  • -104 <= xi, yi <= 104

  • All the points are unique.

Deep-Dive & Conceptual Insights

Core Insight

Floating-point division dy/dx suffers from precision issues. Instead, reduce (dy, dx) by their greatest common divisor (GCD) and store the coprime pair (dy // g, dx // g) as hash map keys.

Real-World Scenario & Production Applications

Computer vision Hough transforms, radar trajectory line detection, geospatial linear feature recognition.

Step-by-Step Execution Trace Table

Anchor PointTarget PointSlope Delta (dx, dy)Coprime Reduction (dy // g, dx // g)Slopes Map for AnchorLocal Collinear Max
(1, 1)(2, 2)dx = 1, dy = 1gcd=1 \implies (1, 1){(1, 1): 1}2 points
(1, 1)(3, 3)dx = 2, dy = 2gcd=2 \implies (1, 1){(1, 1): 2}3 points
(1, 1)(1, 4)dx = 0, dy = 3Vertical line →\to→ (1, 0){(1, 1): 2, (1, 0): 1}3 points
Worked on Paper

The Math, Step by Step

1. The key that names a direction

Fix one point, the anchor (x1,y1)(x_1, y_1)(x1​,y1​). Any other point (x2,y2)(x_2, y_2)(x2​,y2​) lies in some direction from it. Write that direction as the step from the anchor to the point:

dx=x2−x1dy=y2−y1dx = x_2 - x_1 \qquad dy = y_2 - y_1dx=x2​−x1​dy=y2​−y1​

Two points lie on the same line through the anchor when their steps point the same way or exactly opposite ways. The steps (2,1)(2, 1)(2,1) and (4,2)(4, 2)(4,2) and (−2,−1)(-2, -1)(−2,−1) all describe the same line. The code needs one canonical key for each line: a single value that every point of that line produces, and no point of another line produces.

2. Building the key for one pair

The code builds the key in two steps.

First it divides both parts by g=gcd⁡(dx,dy)g = \gcd(dx, dy)g=gcd(dx,dy), the greatest common divisor. Python's math.gcd always returns a non-negative number, and g>0g > 0g>0 here because all points are different. After the division, the two parts have no common factor left. So (4,2)(4, 2)(4,2) and (2,1)(2, 1)(2,1) both become (2,1)(2, 1)(2,1). The key stores dydydy first, as (dy // g, dx // g). The division is exact, because ggg divides both parts.

Then it fixes the sign, because (2,1)(2, 1)(2,1) and (−2,−1)(-2, -1)(−2,−1) are still different pairs. The rule makes the first part positive, or, when the first part is 0, makes the second part positive:

Key (dy // g, dx // g) before the sign fixKind of lineKey after the sign fix
first part >0> 0>0rising or fallingunchanged
first part <0< 0<0rising or fallingboth parts negated
first part =0= 0=0, second part >0> 0>0horizontalunchanged, (0,1)(0, 1)(0,1)
first part =0= 0=0, second part <0< 0<0horizontalnegated to (0,1)(0, 1)(0,1)

A vertical line has dx=0dx = 0dx=0, so g=∣dy∣g = |dy|g=∣dy∣ and the key is (1,0)(1, 0)(1,0) or (−1,0)(-1, 0)(−1,0). The sign fix makes it (1,0)(1, 0)(1,0). No division by zero ever happens.

3. Why equal keys mean one line

Two points with the same key have steps from the anchor that are whole multiples of the same reduced pair. So both lie on the one line through the anchor in that direction. Two points on different lines through the anchor have directions that are not multiples of each other. After dividing by the gcd and fixing the sign, their keys differ. A line through the anchor is fully fixed by one point and its direction, so counting equal keys counts the points on each line.

For each anchor, slopes[key] counts the other points on the line with that key. The line also holds the anchor itself, so it has slopes[key] + 1 points.

4. Why later points are enough, and the small inputs

The inner loop only looks at points with index j>ij > ij>i. That is enough. Take the line with the most points, and let iii be the smallest index among them. When the anchor is point iii, all the other points of that line have larger indices, so they are all counted.

With one or two points, every point is on one line, so the code returns len(points) at once. The loops would return 0 for a single point, because they never run a pair.

5. Example 2 by hand

points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]].

012345

The picture shows the six points, labelled by index. Points 1, 3, 4 and 5 are (3,2)(3, 2)(3,2), (4,1)(4, 1)(4,1), (2,3)(2, 3)(2,3) and (1,4)(1, 4)(1,4). They lie on the line x+y=5x + y = 5x+y=5, which falls by 1 for every step of 1 to the right.

The smallest index on that line is 1, so the anchor (3,2)(3, 2)(3,2) finds it:

jPointdxdxdxdydydyggg(dy // g, dx // g)Key after the sign fixslopes[key]
2(5,3)(5, 3)(5,3)211(1,2)(1, 2)(1,2)(1,2)(1, 2)(1,2)1
3(4,1)(4, 1)(4,1)1−1-1−11(−1,1)(-1, 1)(−1,1)(1,−1)(1, -1)(1,−1)1
4(2,3)(2, 3)(2,3)−1-1−111(1,−1)(1, -1)(1,−1)(1,−1)(1, -1)(1,−1)2
5(1,4)(1, 4)(1,4)−2-2−222(1,−1)(1, -1)(1,−1)(1,−1)(1, -1)(1,−1)3

Row j = 3 shows why the sign fix is needed. Before it, (4,1)(4, 1)(4,1) gives (−1,1)(-1, 1)(−1,1) and (2,3)(2, 3)(2,3) gives (1,−1)(1, -1)(1,−1). Both points are on the same line, but their pairs differ. After the fix, both keys are (1,−1)(1, -1)(1,−1). Row j = 5 shows why the gcd is needed. Its step (−2,2)(-2, 2)(−2,2) is twice the step of row j = 4, and dividing by g=2g = 2g=2 gives the same key.

After row j = 5, the key (1,−1)(1, -1)(1,−1) has count 3, so this line holds 3+1=43 + 1 = 43+1=4 points. No anchor finds a larger count, so the code returns 4, the expected output.

6. Example 1 by hand

points = [[1,1],[2,2],[3,3]]. With the anchor (1,1)(1, 1)(1,1), the point (2,2)(2, 2)(2,2) has step (1,1)(1, 1)(1,1) and key (1,1)(1, 1)(1,1). The point (3,3)(3, 3)(3,3) has step (2,2)(2, 2)(2,2). Its gcd is 2, so its key is also (1,1)(1, 1)(1,1). The count for (1,1)(1, 1)(1,1) reaches 2, so the line holds 2+1=32 + 1 = 32+1=3 points. The code returns 3, the expected output.

7. From the math to the code
MathIn maxPoints
the step from the anchordx, dy = x2 - x1, y2 - y1
g=gcd⁡(dx,dy)g = \gcd(dx, dy)g=gcd(dx,dy)g = math.gcd(dx, dy)
the reduced pair, dydydy firstslope = (dy // g, dx // g)
the sign fixif slope[0] < 0 or (slope[0] == 0 and slope[1] < 0): then negate both parts
points on this line, plus the anchorslopes[slope] += 1 and slopes[slope] + 1
the largest line over all anchorsmax_pts = max(max_pts, slopes[slope] + 1)

The two loops look at every pair once, and each key takes one gcd. Under LeetCode's limits every coordinate difference is at most 2⋅1042 \cdot 10^42⋅104, so one gcd takes a bounded number of steps. So the code takes O(n2)O(n^2)O(n2) time. The map for one anchor holds at most n−1n - 1n−1 keys, so it uses O(n)O(n)O(n) space.

Code Shape
Archetype Code Shape
Python
1if len(points) <= 2:
2 return len(points)
3max_pts = 0
4for i in range(len(points)):
5 slopes = defaultdict(int)
6 x1, y1 = points[i]
7 for j in range(i + 1, len(points)):
8 dx, dy = x2 - x1, y2 - y1
9 g = math.gcd(dx, dy)
10 slope = (dy // g, dx // g), with one fixed sign
11 slopes[slope] += 1
12 max_pts = max(max_pts, slopes[slope] + 1)
13return max_pts

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

Grouping points by slope sounds like it should just be dy / dx in a hash map — until you remember floats lie.

📏 The Analogy: A Surveyor Who Never Trusts Decimals

Imagine a surveyor comparing the steepness of different paths. Two paths are "the same direction" only if their rise-over-run ratios are exactly equal — but a surveyor who measures steepness as a decimal (0.3333...) risks two genuinely-identical directions coming out as 0.33333 and 0.33334 due to rounding, and missing that they're the same line entirely. A careful surveyor never divides at all. Instead, they write the ratio as a fraction and simplify it down to its smallest possible whole-number form — 9/3 and 6/2 both simplify to 3/1, and now they're exactly the same key, no rounding involved.

🔑 The Key Idea in the Code

math.gcd(dx, dy) finds the largest whole number that divides both the rise and the run evenly. Dividing both by it collapses every direction to one, canonical, integer-pair key — (3, 1) and never 0.333.... Two points genuinely on the same line through the anchor will always reduce to the identical pair, so the hash map lookup is 100% reliable instead of "usually right."

  • Floating point slope division precision error: Computing slope as dy / dx uses IEEE 754 floating-point numbers, which suffer precision drift on steep slopes. Normalize the fraction (dy // g, dx // g) using the greatest common divisor (GCD).

  • Vertical line division by zero: When two points share the same x-coordinate (dx=0dx = 0dx=0), division by zero crashes. Normalize vertical slopes to a fixed sentinel like (1, 0).

  • Duplicate points at identical coordinates: When points share the exact same (x,y)(x, y)(x,y) coordinates, slope is undefined; track duplicate point counts separately and add to the maximum collinear line.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Maximum points lying on the same straight line, geometry 2D coordinate plane, line slope collisions.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Invariant: Two lines passing through the same anchor point i with identical reduced slopes (dy/gcd, dx/gcd) represent the exact same line.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • The card's trap, with the blueprint's rule: flip slope when slope[0] < 0 or (slope[0] == 0 and slope[1] < 0), so dy ends up positive (or dy == 0 with dx positive).

  • Vertical and horizontal lines need no special case: gcd(0, dy) is abs(dy), so a vertical line becomes (1, 0) after the sign fix, and a horizontal one becomes (0, 1).

  • Count the anchor too: the line through points[i] holds slopes[slope] + 1 points; without the + 1 every answer is one short.

The 60-Second Interview Pitch

Say this out loud before you type a single line

I'd use a Canonical Key. A line through two points is fixed by one anchor point and a direction, so for each anchor points[i] I fill a fresh map slopes with the direction to every later point points[j]. I write that direction as the reduced integer pair (dy // g, dx // g) with g = gcd(dx, dy), so directions such as (2, 4) and (1, 2) get the same key. Two points lie on the same line through the anchor exactly when their pairs match, and integers compare exactly, unlike rounded float slopes. The trap is the sign: (1, -2) and (-1, 2) are the same direction, so I flip the pair whenever dy is negative, or dy is zero and dx is negative; otherwise one line is counted as two. The best line through the anchor has slopes[slope] + 1 points, counting the anchor itself. That's O(N²) time and O(N) space.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(N^2)

Look at the execution steps: For each point i (N choices), computes normalized slope (dy, dx) via GCD with all other N - 1 points j. Hash map tracks slope frequencies. Max slope count gives max collinear points through point i. Total N * (N - 1) slope calculations.

SPACE COMPLEXITY

O(N)

Look at memory allocations: Call stack uses O(1) Iterative. Hash map storing at most N - 1 reduced slope pairs per anchor point.

Formal Recurrence Relation

T(N) = ∑_{i=1}^N (N - i) = O(N^2)

Derivation Progression

Anchor Point Loop

N anchor points

Fixes point i as origin.

Normalized Slope Computation

g = gcd(dx, dy), (dy // g, dx // g)

Reduces the slope with Euclid's algorithm. Differences are at most 2 * 10^4, so one gcd takes at most 20 remainder steps (the worst pair is 17711 and 10946): a constant under these limits, so each pair costs O(1). (With unbounded coordinates C, the total would be O(N^2 log C).)

Slope Frequency Tally

slopes[(dy // g, dx // g)] += 1

Tally collinear lines through anchor point in O(1) map operation.

Variable Definitions

NNN

Total number of 2D points in the input array

Memory Architecture & Bounds

🟣 Call Stack

O(1) Iterative

🔵 Auxiliary Heap

O(N) Hash map of reduced slope fractions

🟢 Output Space

O(1) Max points integer

Boundary Best / Worst Cases

Best Case

O(1)O(1)O(1) for N <= 2.

Average Case

O(N2)O(N^2)O(N2).

Worst Case

O(N2)O(N^2)O(N2) general case.

Recurrence Tree Topology

Recurrence Tree Topology
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Key phrasing: the largest count of points sharing one straight line. Geometry trigger: slope collinearity. Points p1,p2,p3p_1, p_2, p_3p1​,p2​,p3​ are collinear if slope(p1,p2)==slope(p1,p3)\text{slope}(p_1, p_2) == \text{slope}(p_1, p_3)slope(p1​,p2​)==slope(p1​,p3​). The fatal junior trap is computing float(dy) / dx: floating-point division introduces IEEE-754 precision drift and rounding errors, causing identical slopes to hash to different buckets. A Senior SWE immediately implements Coprime GCD Slope Normalization: represent the slope as a canonical coprime integer pair (Δygcd⁡(Δx,Δy),Δxgcd⁡(Δx,Δy))(\frac{\Delta y}{\gcd(\Delta x, \Delta y)}, \frac{\Delta x}{\gcd(\Delta x, \Delta y)})(gcd(Δx,Δy)Δy​,gcd(Δx,Δy)Δx​).

CONSTRAINTS & BOUNDS

1≤points.length≤3001 \le points.length \le 3001≤points.length≤300. With N=300N=300N=300, an O(N2)O(N^2)O(N2) pairwise slope aggregation using a local hash map takes 3002=9×104300^2 = 9 \times 10^43002=9×104 pair checks.

FAANG PRODUCTION TRAPS & EDGE CASES

Edge case: N≤2N \le 2N≤2 immediately returns NNN. At scale, memory stays small because slopes is rebuilt for each anchor: it never holds more than N−1N - 1N−1 keys, although O(N2)O(N^2)O(N2) pairs are examined in total.

© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•