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•Advanced Data Structures
MediumLC 547

Number of Provinces (LeetCode 547)

Target Frequency:AmazonMicrosoftGoogle

n cities may be linked by direct connections, and connections chain: if a links to b and b links to c, then a and c count as linked too, even without a direct edge.

A province is one maximal cluster of cities reachable from each other this way, with no city belonging to two clusters.

The input is isConnected, an n x n matrix in which isConnected[i][j] = 1 marks a direct connection between city i and city j (0 otherwise).

Report how many provinces exist in total.

Worked Examples

Example 1
Input:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
Output:2
012
Explanation: Cities 0 and 1 are linked; city 2 stands alone. That makes 2 provinces.
Example 2
Input:isConnected = [[1,0,0],[0,1,0],[0,0,1]]
Output:3
012
Explanation: No city is linked to another, so each one is its own province.

⚖️Formal Constraints & Bounds

  • 1 <= n <= 200

  • n == isConnected.length

  • n == isConnected[i].length

  • isConnected[i][j] is 1 or 0.

  • isConnected[i][i] == 1

  • isConnected[i][j] == isConnected[j][i]

Deep-Dive & Conceptual Insights

Core Insight

Every successful union between disjoint roots reduces the total component count by exactly 1.

Real-World Scenario & Production Applications

Telecom regional network partitioning, social network friend cluster count.

Subproblems & Recurrence Decomposition3 Phases

🧩Subproblem 1: Path Compression Find Invariant

Locate the canonical root of node i, flattening the tree pointer structure during recursion so future lookups execute in O(alpha(N)) nearly constant time.

Mathematical Recurrence / Code Invariant
def find(i):
    if parent[i] != i:
        parent[i] = find(parent[i])  # Path compression
    return parent[i]

Step-by-Step Execution Trace Table

Edge (i, j)find(i) Rootfind(j) RootActionRemaining Provinces
Initial---3
(0, 1) = 101Union(0, 1)2
(0, 2) = 002No connection2
(1, 2) = 002No connection2
Code Shape
Archetype Code Shape
Python
1parent = list(range(n))
2provinces = n
3for i in range(n):
4 for j in range(i + 1, n):
5 if isConnected[i][j] and union(i, j):
6 provinces -= 1
7return provinces

Conceptual Narrative

Number of Provinces counts connected components in an undirected adjacency matrix. Initializing N independent components and decrementing upon every successful union solves the problem in near-linear time.

🧭 Conceptual Foundation & Pattern Intuition

We are given an N×NN \times NN×N symmetric adjacency matrix where isConnected[i][j] == 1 indicates a direct bidirectional link between city iii and city jjj. A "province" is a maximal connected component of directly or indirectly linked cities. Instead of running NNN separate graph traversals (BFS/DFS) with visited sets, Disjoint Set Union provides a purely algebraic accounting solution:

  1. Initialize the system with NNN independent provinces (count = n), where each city is its own root (parent[i] = i).
  2. Iterate through all pairs (i,j)(i, j)(i,j) with j>ij > ij>i (exploiting upper-triangular symmetry).
  3. Whenever isConnected[i][j] == 1, attempt to unite city iii and city jjj.
  4. If find(i) != find(j), the two cities belonged to previously separate provinces. Merging them decreases the total province count by exactly 1 (count -= 1). If they already shared a root, no count change occurs.
🤝 The Analogy: Treaty Mergers Among Feudal Kingdoms

Imagine NNN sovereign kingdoms on a continent. At sunrise, there are exactly NNN independent flags flying. Throughout the day, ambassadors sign mutual defense treaties (isConnected[i][j] == 1). When two kingdoms from completely different alliances sign a treaty, their alliances merge into a single commonwealth, and one flag is retired (total independent nations decreases by 1). If two kingdoms that already belong to the same commonwealth sign a treaty, no new land is added and no flags are retired. At sunset, the remaining flag count is the total number of provinces.

🔑 Why It Works

Because dsu.union() returns a boolean indicating whether a genuine merge occurred, tracking component cardinality requires zero post-processing or hash-set deduplication.

  • Double-checking edges: Checking both isConnected[i][j] and isConnected[j][i] doubles union operations; scan upper triangle range(i + 1, n).

  • Forgetting path compression: Omitting parent[x] = find(parent[x]) in find() degrades tree height to O(N)O(N)O(N), slowing union operations.

  • Counting roots at the end without path compression: Calling len(set(parent)) at the end without calling find() on all nodes returns uncompressed intermediate parents.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Counting connected components from an adjacency matrix.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Invariant: total components equals N minus total successful union operations.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • Iterating symmetric matrix twice: only iterate j > i to avoid redundant comparisons.

The 60-Second Interview Pitch

Say this out loud before you type a single line

"I initialize DSU with n individual components (provinces = n). For each pair (i, j) where isConnected[i][j] == 1, I find their roots. If find(i) != find(j), I union them and decrement provinces -= 1. I return provinces. Runs in O(N² · α(N)) time and O(N) space."

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(N^2 · alpha(N))

Look at the execution steps: Examines N x N adjacency matrix. For each connection where isConnected[i][j] == 1, calls union(i, j) on DSU of size N. Total N^2 edge checks.

SPACE COMPLEXITY

O(N) Auxiliary

Look at memory allocations: parent and rank hold N entries each, O(N). find calls itself once per level of a tree, and union by rank keeps every tree at most log2 N + 1 levels tall, so the call stack is O(log N). The answer is one count, O(1).

Formal Recurrence Relation

T(N) = N^2 · O(α(N)) = O(N^2)

Derivation Progression

Matrix Edge Scan

for i, j ∈ [0, N-1]

Scans all N^2 matrix cells.

DSU Union Operation

if isConnected[i][j]: union(i, j)

Merges connected provinces in O(alpha(N)) time.

Component Count

count decrements on successful union

Tracks number of disjoint province sets.

Variable Definitions

NNN

Number of cities (dimension of N × N adjacency matrix)

α(N)α(N)α(N)

Inverse Ackermann function (α ≤ 4)

Memory Architecture & Bounds

🟣 Call Stack

O(log N) Recursive find, union by rank

🔵 Auxiliary Heap

O(N) Parent array of size N

🟢 Output Space

O(1) Province count integer

Boundary Best / Worst Cases

Best Case

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

Average Case

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

Worst Case

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

Recurrence Tree Topology

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

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "directly or indirectly connected", "total number of provinces". Connected component counting on an adjacency matrix. While BFS/DFS work well, DSU provides a stateful mechanism: start with NNN isolated components; every successful union operation decrements the component counter by 1.

CONSTRAINTS & BOUNDS

N≤200N \le 200N≤200. Adjacency matrix N×NN \times NN×N. Time budget O(N2⋅α(N))O(N^2 \cdot \alpha(N))O(N2⋅α(N)) takes <5< 5<5ms.

FAANG PRODUCTION TRAPS & EDGE CASES

Symmetric matrix redundancy: only iterate over upper triangular entries j>ij > ij>i where isConnected[i][j]==1isConnected[i][j] == 1isConnected[i][j]==1.

Theory Context•Advanced Data Structures
MediumLC 547

Number of Provinces (LeetCode 547)

Target Frequency:AmazonMicrosoftGoogle

n cities may be linked by direct connections, and connections chain: if a links to b and b links to c, then a and c count as linked too, even without a direct edge.

A province is one maximal cluster of cities reachable from each other this way, with no city belonging to two clusters.

The input is isConnected, an n x n matrix in which isConnected[i][j] = 1 marks a direct connection between city i and city j (0 otherwise).

Report how many provinces exist in total.

Worked Examples

Example 1
Input:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
Output:2
012
Explanation: Cities 0 and 1 are linked; city 2 stands alone. That makes 2 provinces.
Example 2
Input:isConnected = [[1,0,0],[0,1,0],[0,0,1]]
Output:3
012
Explanation: No city is linked to another, so each one is its own province.

⚖️Formal Constraints & Bounds

  • 1 <= n <= 200

  • n == isConnected.length

  • n == isConnected[i].length

  • isConnected[i][j] is 1 or 0.

  • isConnected[i][i] == 1

  • isConnected[i][j] == isConnected[j][i]

Deep-Dive & Conceptual Insights

Core Insight

Every successful union between disjoint roots reduces the total component count by exactly 1.

Real-World Scenario & Production Applications

Telecom regional network partitioning, social network friend cluster count.

Subproblems & Recurrence Decomposition3 Phases

🧩Subproblem 1: Path Compression Find Invariant

Locate the canonical root of node i, flattening the tree pointer structure during recursion so future lookups execute in O(alpha(N)) nearly constant time.

Mathematical Recurrence / Code Invariant
def find(i):
    if parent[i] != i:
        parent[i] = find(parent[i])  # Path compression
    return parent[i]

Step-by-Step Execution Trace Table

Edge (i, j)find(i) Rootfind(j) RootActionRemaining Provinces
Initial---3
(0, 1) = 101Union(0, 1)2
(0, 2) = 002No connection2
(1, 2) = 002No connection2
Code Shape
Archetype Code Shape
Python
1parent = list(range(n))
2provinces = n
3for i in range(n):
4 for j in range(i + 1, n):
5 if isConnected[i][j] and union(i, j):
6 provinces -= 1
7return provinces

Conceptual Narrative

Number of Provinces counts connected components in an undirected adjacency matrix. Initializing N independent components and decrementing upon every successful union solves the problem in near-linear time.

🧭 Conceptual Foundation & Pattern Intuition

We are given an N×NN \times NN×N symmetric adjacency matrix where isConnected[i][j] == 1 indicates a direct bidirectional link between city iii and city jjj. A "province" is a maximal connected component of directly or indirectly linked cities. Instead of running NNN separate graph traversals (BFS/DFS) with visited sets, Disjoint Set Union provides a purely algebraic accounting solution:

  1. Initialize the system with NNN independent provinces (count = n), where each city is its own root (parent[i] = i).
  2. Iterate through all pairs (i,j)(i, j)(i,j) with j>ij > ij>i (exploiting upper-triangular symmetry).
  3. Whenever isConnected[i][j] == 1, attempt to unite city iii and city jjj.
  4. If find(i) != find(j), the two cities belonged to previously separate provinces. Merging them decreases the total province count by exactly 1 (count -= 1). If they already shared a root, no count change occurs.
🤝 The Analogy: Treaty Mergers Among Feudal Kingdoms

Imagine NNN sovereign kingdoms on a continent. At sunrise, there are exactly NNN independent flags flying. Throughout the day, ambassadors sign mutual defense treaties (isConnected[i][j] == 1). When two kingdoms from completely different alliances sign a treaty, their alliances merge into a single commonwealth, and one flag is retired (total independent nations decreases by 1). If two kingdoms that already belong to the same commonwealth sign a treaty, no new land is added and no flags are retired. At sunset, the remaining flag count is the total number of provinces.

🔑 Why It Works

Because dsu.union() returns a boolean indicating whether a genuine merge occurred, tracking component cardinality requires zero post-processing or hash-set deduplication.

  • Double-checking edges: Checking both isConnected[i][j] and isConnected[j][i] doubles union operations; scan upper triangle range(i + 1, n).

  • Forgetting path compression: Omitting parent[x] = find(parent[x]) in find() degrades tree height to O(N)O(N)O(N), slowing union operations.

  • Counting roots at the end without path compression: Calling len(set(parent)) at the end without calling find() on all nodes returns uncompressed intermediate parents.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

Counting connected components from an adjacency matrix.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Invariant: total components equals N minus total successful union operations.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • Iterating symmetric matrix twice: only iterate j > i to avoid redundant comparisons.

The 60-Second Interview Pitch

Say this out loud before you type a single line

"I initialize DSU with n individual components (provinces = n). For each pair (i, j) where isConnected[i][j] == 1, I find their roots. If find(i) != find(j), I union them and decrement provinces -= 1. I return provinces. Runs in O(N² · α(N)) time and O(N) space."

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(N^2 · alpha(N))

Look at the execution steps: Examines N x N adjacency matrix. For each connection where isConnected[i][j] == 1, calls union(i, j) on DSU of size N. Total N^2 edge checks.

SPACE COMPLEXITY

O(N) Auxiliary

Look at memory allocations: parent and rank hold N entries each, O(N). find calls itself once per level of a tree, and union by rank keeps every tree at most log2 N + 1 levels tall, so the call stack is O(log N). The answer is one count, O(1).

Formal Recurrence Relation

T(N) = N^2 · O(α(N)) = O(N^2)

Derivation Progression

Matrix Edge Scan

for i, j ∈ [0, N-1]

Scans all N^2 matrix cells.

DSU Union Operation

if isConnected[i][j]: union(i, j)

Merges connected provinces in O(alpha(N)) time.

Component Count

count decrements on successful union

Tracks number of disjoint province sets.

Variable Definitions

NNN

Number of cities (dimension of N × N adjacency matrix)

α(N)α(N)α(N)

Inverse Ackermann function (α ≤ 4)

Memory Architecture & Bounds

🟣 Call Stack

O(log N) Recursive find, union by rank

🔵 Auxiliary Heap

O(N) Parent array of size N

🟢 Output Space

O(1) Province count integer

Boundary Best / Worst Cases

Best Case

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

Average Case

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

Worst Case

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

Recurrence Tree Topology

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

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "directly or indirectly connected", "total number of provinces". Connected component counting on an adjacency matrix. While BFS/DFS work well, DSU provides a stateful mechanism: start with NNN isolated components; every successful union operation decrements the component counter by 1.

CONSTRAINTS & BOUNDS

N≤200N \le 200N≤200. Adjacency matrix N×NN \times NN×N. Time budget O(N2⋅α(N))O(N^2 \cdot \alpha(N))O(N2⋅α(N)) takes <5< 5<5ms.

FAANG PRODUCTION TRAPS & EDGE CASES

Symmetric matrix redundancy: only iterate over upper triangular entries j>ij > ij>i where isConnected[i][j]==1isConnected[i][j] == 1isConnected[i][j]==1.

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