MindForge
MindForge
DashboardHelp & Support
Dashboard
MindForge

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Union-Find (Disjoint Set Union)
Course contents

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Browsing without an account — progress is saved in this browser only.Sign in to save it

Union-Find (Disjoint Set Union)

Reading105 min

Picture a party where you keep introducing people. Every time you introduce two strangers, their two friend circles merge into one. At any moment, you might ask "are these two people in the same friend circle now?" Union-Find (Disjoint Set Union, or DSU) answers exactly that question, and merges groups, both in near-constant time. It replaces slower BFS/DFS connectivity checks, and it's the difference between a working solution and a timeout on problems where connections arrive one at a time, like Number of Islands II.

Find: walking up to the group's leader, with a shortcut

find(x) walks up parent pointers from x until it reaches the root of x's tree, a node that is its own parent. That root acts as the "name" of the whole group. Without any optimization, this walk can take O(n) steps on a long, chain-like tree. Path compression fixes that: while walking up to find the root, rewire every node you pass through to point directly at the root. The next find call through any of those nodes is then instant.

def find(self, x: int) -> int:
    if self.parent[x] != x:
        self.parent[x] = self.find(self.parent[x])   # path compression
    return self.parent[x]

This looks like a simple recursive one-liner, but it does real work: the recursive call returns the root, and the assignment flattens x's pointer to point straight at that root, permanently shortening the path for every future call that passes through x.

Remember: find() walks up to the root. Path compression rewires every node it passes through to point directly at that root, so the next lookup is instant.

Sign in to try this knowledge check.

Union by rank: keep the merged tree shallow

union(x, y) merges the two groups containing x and y by attaching one tree's root under the other's. Attaching them arbitrarily can, over many merges, build a tall, unbalanced tree. Union by rank (or by size) always attaches the shorter tree under the taller one's root, keeping the whole structure shallow.

def union(self, x: int, y: int) -> None:
    root_x, root_y = self.find(x), self.find(y)
    if root_x == root_y:
        return   # already connected
    if self.rank[root_x] < self.rank[root_y]:
        root_x, root_y = root_y, root_x
    self.parent[root_y] = root_x
    if self.rank[root_x] == self.rank[root_y]:
        self.rank[root_x] += 1

Combined, path compression and union by rank give an amortized time of O(α(n)) per operation, where α is the inverse Ackermann function. For any n you could realistically encounter, α(n) is at most 4, which is why this is described as "nearly O(1)."

Remember: always attach the shorter tree under the taller one's root. Combined with path compression, this makes every operation nearly O(1).

Sign in to try this knowledge check.

Using union-find to catch a cycle as you build a graph

DSU gives a clean way to detect a cycle while building a graph one edge at a time: before adding an edge (u, v), check whether find(u) == find(v). If they're already in the same group, this edge would create a cycle, so either skip it, or, if you add it anyway, you've just confirmed a cycle exists. This is exactly how Kruskal's minimum-spanning-tree algorithm decides which edges to keep, and it's the core trick behind Graph Valid Tree below.

def has_cycle_on_add(self, u: int, v: int) -> bool:
    if self.find(u) == self.find(v):
        return True   # adding this edge would close a cycle
    self.union(u, v)
    return False

Remember: if find(u) equals find(v) before you union them, adding that edge would close a cycle.

Sign in to try this knowledge check.

Number of Connected Components in an Undirected Graph

LeetCode 323 · Number of Connected Components · DSU

Start with n components, since every node begins isolated. Each edge that connects two different components reduces the component count by exactly one; an edge between two nodes already in the same component changes nothing.

Approach: Initialize DSU with n singleton sets. Union across every edge; decrement a running count directly whenever a union actually merges two different roots.

class DSU:
    def __init__(self, n: int) -> None:
        self.parent = list(range(n))
        self.rank = [0] * n
        self.count = n   # number of distinct components

    def find(self, x: int) -> int:
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def union(self, x: int, y: int) -> None:
        root_x, root_y = self.find(x), self.find(y)
        if root_x == root_y:
            return
        if self.rank[root_x] < self.rank[root_y]:
            root_x, root_y = root_y, root_x
        self.parent[root_y] = root_x
        if self.rank[root_x] == self.rank[root_y]:
            self.rank[root_x] += 1
        self.count -= 1


def count_components(n: int, edges: list[list[int]]) -> int:
    dsu = DSU(n)
    for u, v in edges:
        dsu.union(u, v)
    return dsu.count

Complexity: O(n + E · α(n)) time, O(n) space. This DSU class is the reusable template for all four problems in this lesson.

Common mistakes: Recomputing the component count with a separate pass calling find(i) on every node, instead of tracking it incrementally inside union. Forgetting path compression, which degrades find to O(n) on adversarial inputs, such as a chain graph.

Remember: start every node as its own component, then decrement the count by exactly one on every union that actually merges two different roots.

Sign in to try this knowledge check.

Longest Consecutive Sequence

LeetCode 128 · Longest Consecutive Sequence · DSU

Values that are consecutive integers (x and x+1) belong in the same "run." Union every value with value + 1 whenever that neighbor is present in the array; the answer is then the size of the largest resulting component. (A hash-set expand-from-start approach is O(n) and usually the preferred interview answer, but DSU is worth knowing since it's this lesson's topic, and the same "union adjacent related values" idea shows up elsewhere.)

Approach: Map each value to an index. Union value with value + 1 whenever both are present. Track component sizes in the DSU so "largest run" is a direct lookup.

def longest_consecutive(nums: list[int]) -> int:
    if not nums:
        return 0

    unique_nums = list(set(nums))
    index_of = {num: i for i, num in enumerate(unique_nums)}
    n = len(unique_nums)

    parent = list(range(n))
    size = [1] * n

    def find(x: int) -> int:
        if parent[x] != x:
            parent[x] = find(parent[x])
        return parent[x]

    def union(x: int, y: int) -> None:
        rx, ry = find(x), find(y)
        if rx == ry:
            return
        if size[rx] < size[ry]:
            rx, ry = ry, rx
        parent[ry] = rx
        size[rx] += size[ry]

    for num in unique_nums:
        if num + 1 in index_of:
            union(index_of[num], index_of[num + 1])

    return max(size[find(i)] for i in range(n))

Complexity: O(n · α(n)) time, O(n) space. The pure hash-set approach (expand upward only from numbers that have no num - 1 predecessor) reaches plain O(n) without any DSU overhead. Mention both, and lead with whichever fits the interviewer's follow-up.

Common mistakes: Unioning by raw value instead of by index, since the DSU arrays are indexed 0..n-1, not by arbitrary integer value. Forgetting to dedupe the input first, which wastes work reprocessing duplicate values.

Remember: union each value with value+1 when both exist; the biggest resulting group size is the longest consecutive run.

Sign in to try this knowledge check.

Graph Valid Tree

LeetCode 261 · Graph Valid Tree · DSU

A graph with n nodes is a valid tree only if it has exactly n - 1 edges AND is fully connected, meaning no cycles and no separate pieces. DSU checks both conditions in one pass: if any edge connects two nodes already in the same component, that's a cycle, and the graph is immediately invalid.

Approach: A quick edge-count check first (len(edges) != n - 1 fails immediately, saving wasted DSU work). Then union each edge, failing fast the moment a cycle is detected.

def valid_tree(n: int, edges: list[list[int]]) -> bool:
    if len(edges) != n - 1:
        return False   # too many edges (cycle) or too few (disconnected)

    parent = list(range(n))

    def find(x: int) -> int:
        if parent[x] != x:
            parent[x] = find(parent[x])
        return parent[x]

    for u, v in edges:
        root_u, root_v = find(u), find(v)
        if root_u == root_v:
            return False   # cycle detected
        parent[root_v] = root_u

    return True

Complexity: O(n · α(n)) time, O(n) space.

Common mistakes: Skipping the len(edges) != n - 1 pre-check and relying purely on cycle detection: a graph can be cycle-free but still disconnected (a forest of separate trees), and the edge-count check is what rules that out cheaply. Forgetting that a valid tree also requires full connectivity, not just the absence of cycles.

Remember: a valid tree needs exactly n-1 edges AND no cycle. The edge count alone doesn't guarantee connectivity, and no-cycle alone doesn't either; you need both checks.

Sign in to try this knowledge check.

Number of Islands II

LeetCode 305 · Number of Islands II · DSU · Hard

Land cells are added one at a time, and after each addition you need the current island count. Recomputing with BFS/DFS after every single addition costs O(n) per query. DSU processes each addition in near-O(1), which is the entire reason DSU exists for dynamic (incremental) connectivity problems, as opposed to static ones where BFS/DFS is simpler.

Approach: Maintain a DSU over the grid's flattened cell indices, plus a land set tracking which cells are filled. On each new land cell, increment the island count by 1 (a brand-new component), then union with any of its 4 already-land neighbors, decrementing the count once per successful merge.

def num_islands2(m: int, n: int, positions: list[list[int]]) -> list[int]:
    parent = {}
    rank = {}
    land = set()
    result = []
    count = 0

    def find(x: int) -> int:
        if parent[x] != x:
            parent[x] = find(parent[x])
        return parent[x]

    def union(x: int, y: int) -> bool:
        rx, ry = find(x), find(y)
        if rx == ry:
            return False
        if rank[rx] < rank[ry]:
            rx, ry = ry, rx
        parent[ry] = rx
        if rank[rx] == rank[ry]:
            rank[rx] += 1
        return True

    for r, c in positions:
        idx = r * n + c
        if idx in land:
            result.append(count)   # duplicate addition, no change
            continue
        land.add(idx)
        parent[idx] = idx
        rank[idx] = 0
        count += 1

        for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
            nr, nc = r + dr, c + dc
            n_idx = nr * n + nc
            if 0 <= nr < m and 0 <= nc < n and n_idx in land:
                if union(idx, n_idx):
                    count -= 1

        result.append(count)

    return result

Complexity: O(k · α(k)) time for k position updates, O(k) space (only land cells get DSU entries, via a dict-based sparse DSU, not a full m*n array).

Common mistakes: Allocating a dense parent array of size m*n when a dict keyed by only the cells actually visited is simpler and avoids wasted memory on large sparse grids. Forgetting to handle duplicate positions in the input, since the same cell can appear twice and must not be double-counted as a new island. Not decrementing count on every successful union; each merge reduces the island count by exactly one, and a single new cell can merge with up to 4 neighbors at once.

Remember: each new land cell starts as its own island (+1), then merges with any land neighbors (-1 per merge). A sparse dict-based DSU avoids allocating the whole grid upfront.

Sign in to try this knowledge check.

The four problems in this lesson split along one axis: is the graph built once (Number of Connected Components, Graph Valid Tree), or does it grow incrementally (Longest Consecutive Sequence's value-by-value unions, Number of Islands II's cell-by-cell additions)? For the one-time case, BFS/DFS is usually just as good as DSU, and sometimes simpler to write. DSU earns its place specifically when connectivity needs to be checked between additions, not only once at the very end.

PreviousTopological Sort and Cycle DetectionNextPractice Test: Trees, Heaps and Graphs

Course progress

0%
0 of 177 modules complete

On this page

  • Find: walking up to the group's leader, with a shortcut
  • Union by rank: keep the merged tree shallow
  • Using union-find to catch a cycle as you build a graph
  • Number of Connected Components in an Undirected Graph
  • Longest Consecutive Sequence
  • Graph Valid Tree
  • Number of Islands II