Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Coding Interview Patterns  Module 22 – Union-find (disjoint sets)

Connectivity and redundant edges

Find the line that closes the only loop of a network, answer connectivity questions as links arrive, and count islands as a bay is filled cell by cell.

  • Intermediate
  • 30 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, quickjs 0.32.0, Java 25, Clang 21.0.0 and Go 1.27.1
  • By MySmartCoPilot
Free core, Pro depth: 10 of 30 minutes free
Free: Two problems from one growing network · The brute force, and what it costs · The key idea: a failed union, and a count that moves by one · 2 more sections. With a pass: 3 in-depth parts and 3 interview answers, about 20 minutes.

What you will learn

  • Find the line that closes the only loop of a network with one union per line
  • Answer whether two items are connected at any moment while links arrive
  • Count islands after each filled cell by numbering the cells r · cols + c
  • Prove that the first union that fails is the line to switch off
  • Extend the method to one-way feeders, lines that fail and spare cables

Before you start

What you’ll learn · Before you start

What you will learn

  • Find the line that closes the only loop of a network with one union per line
  • Answer whether two items are connected at any moment while links arrive
  • Count islands after each filled cell by numbering the cells r · cols + c
  • Prove that the first union that fails is the line to switch off
  • Extend the method to one-way feeders, lines that fail and spare cables

Before you start

On this page

Redundant edges are links whose two ends were connected already, and union-find finds them as the links arrive. Put each link into a union-find in the order it was made: the first one whose union returns False closed a loop. The same structure answers connectivity questions at any moment, because two items are connected exactly when find returns the same root for both. A grid becomes a union-find once cell (r, c) gets the number r · cols + c: a new land cell adds one island, and each union with a land neighbour that returns True takes one away.

Both problems below build on the 20-line template of the union-find lesson.

Two problems from one growing network

Problem A: the line that closed the loop. An electricity board joined n substations, numbered 1 to n, with lines that carry power both ways, and logged each line as it was built. The plan was a tree, n − 1 lines and no loop, but the log has n lines, so there is exactly one loop. Switching off any line of that loop leaves a tree: return the one built last. Limits: 2 ≤ n ≤ 200,000; each line joins two different substations, and together they connect all of them.

  1. n = 5 with (1, 2), (2, 3), (3, 4), (1, 4), (4, 5) gives (1, 4).
  2. n = 6 with (2, 3), (1, 2), (4, 5), (3, 1), (5, 6), (4, 1) gives (3, 1): the loop closes at the fourth line, and the two lines after it are still needed.
  3. n = 2 with (1, 2), (2, 1) gives (2, 1): two lines between one pair form a loop.

Problem B: islands as a bay is filled. A bay of rows × cols cells is all water, and a reclamation project fills one cell at a time; a cell may be listed again. Land cells that share a side form one island. After each cell, report how many islands there are. Limits: 1 ≤ rows, cols ≤ 1,000 and at most 100,000 cells.

  1. 3 × 3 with (0, 0), (0, 2), (2, 1), (0, 1), (1, 1), (0, 1) gives 1, 2, 3, 2, 1, 1.
  2. 1 × 1 with (0, 0) twice gives 1, 1.
  3. 3 × 3 with (0, 1), (1, 0), (1, 2), (2, 1), (1, 1) gives 1, 2, 3, 4, 1: the centre joins four islands at once.
Five substations whose 4th line, from 1 to 4, closes a loop; then a 3 by 3 bay going from 3 islands to 2 and to 1.A: the line that closed the loop1st2nd3rd4th5th12345The 1st to 3rd lines already join 1 and 4, sounion(1, 4) returns False: the 4th closes the loop.B: islands after cells 3, 4 and 5cell (2, 1)3 islandscell (0, 1)2 islandscell (1, 1)1 islandShaded: land. Thick outline: the cell just filled.

The first example of each problem

Text description of the diagram

The upper panel shows problem A on its first example. Substations 1, 2, 3 and 4 sit at the corners of a square and substation 5 to the left of 4. The lines are labelled in the order they were built: the 1st joins 1 and 2, the 2nd joins 2 and 3, the 3rd joins 3 and 4, the 4th joins 1 and 4, and the 5th joins 4 and 5. The 4th line is dashed: when it was built, the first three lines already connected 1 and 4, so union(1, 4) returned False and that line closed the only loop.

The lower panel shows problem B on its first example as three small grids of 3 by 3 cells. Land cells are shaded, and the cell just filled has a thick outline.

  1. After the 3rd cell, (2, 1), the land is (0, 0), (0, 2) and (2, 1): three islands of one cell each.
  2. After the 4th cell, (0, 1), the top row is all land and forms one island, and (2, 1) is another: two islands.
  3. After the 5th cell, (1, 1), the middle cell joins the top row to (2, 1): one island.

The brute force, and what it costs

For A, switch off each line in turn, the last one first, and search whether the other n − 1 lines still reach every substation. For B, fill the cell and flood every island of the bay again. Both are plainly right, and both are quadratic:

Both brute forces, with the work counted Python · brute/brute_force.py
# Both problems by brute force, with the work counted. Correct by construction, so they are what faster code is
# checked against.
from collections import deque


def connects_all(n, lines):
    """BFS from substation 1 over these lines: do they reach all n substations? Also the line ends read."""
    neighbours = [[] for _ in range(n + 1)]
    for a, b in lines:
        neighbours[a].append(b)
        neighbours[b].append(a)
    seen = [False] * (n + 1)
    seen[1] = True
    queue, reached, reads = deque([1]), 1, 0
    while queue:
        for other in neighbours[queue.popleft()]:
            reads += 1
            if not seen[other]:
                seen[other] = True
                reached += 1
                queue.append(other)
    return reached == n, reads


def loop_line_brute(n, lines):
    """Switch off each line in turn, the last built first, until the other n - 1 lines still reach every substation."""
    work = 0
    for k in range(len(lines) - 1, -1, -1):
        ok, reads = connects_all(n, lines[:k] + lines[k + 1:])
        work += reads
        if ok:
            return lines[k], work
    return None, work


def count_islands(rows, cols, land):
    """Flood every island of the whole grid once; also the cells looked at."""
    seen = [[False] * cols for _ in range(rows)]
    islands, looked = 0, 0
    for r in range(rows):
        for c in range(cols):
            looked += 1
            if land[r][c] and not seen[r][c]:
                islands += 1
                seen[r][c] = True
                queue = deque([(r, c)])
                while queue:
                    y, x = queue.popleft()
                    for ny, nx in ((y - 1, x), (y + 1, x), (y, x - 1), (y, x + 1)):
                        if 0 <= ny < rows and 0 <= nx < cols:
                            looked += 1
                            if land[ny][nx] and not seen[ny][nx]:
                                seen[ny][nx] = True
                                queue.append((ny, nx))
    return islands, looked


def islands_brute(rows, cols, cells):
    """Fill each cell, then count every island of the grid again."""
    land = [[False] * cols for _ in range(rows)]
    counts, work = [], 0
    for r, c in cells:
        land[r][c] = True
        islands, looked = count_islands(rows, cols, land)
        counts.append(islands)
        work += looked
    return counts, work


print("A: the line that closed the loop")
for n, lines in [
    (5, [(1, 2), (2, 3), (3, 4), (1, 4), (4, 5)]),
    (6, [(2, 3), (1, 2), (4, 5), (3, 1), (5, 6), (4, 1)]),
    (2, [(1, 2), (2, 1)]),
]:
    line, work = loop_line_brute(n, lines)
    print(f"  n = {n}: {line}, after {work} line ends read")

print("B: islands after each filled cell")
for rows, cols, cells in [
    (3, 3, [(0, 0), (0, 2), (2, 1), (0, 1), (1, 1), (0, 1)]),
    (1, 1, [(0, 0), (0, 0)]),
    (3, 3, [(0, 1), (1, 0), (1, 2), (2, 1), (1, 1)]),
]:
    counts, work = islands_brute(rows, cols, cells)
    print(f"  {rows} x {cols}: {counts}, after {work} cells looked at")

print("A when the loop closes early: a doubled first line, then a long chain")
for n in (500, 1_000, 2_000):
    lines = [(1, 2), (2, 1)] + [(i, i + 1) for i in range(2, n)]
    line, work = loop_line_brute(n, lines)
    print(f"  n = {n:>5,}: {line}, after {work:>9,} line ends read")

Output

A: the line that closed the loop
  n = 5: (1, 4), after 16 line ends read
  n = 6: (3, 1), after 26 line ends read
  n = 2: (2, 1), after 2 line ends read
B: islands after each filled cell
  3 x 3: [1, 2, 3, 2, 1, 1], after 105 cells looked at
  1 x 1: [1, 1], after 2 cells looked at
  3 x 3: [1, 2, 3, 4, 1], after 91 cells looked at
A when the loop closes early: a doubled first line, then a long chain
  n =   500: (2, 1), after   250,496 line ends read
  n = 1,000: (2, 1), after 1,000,996 line ends read
  n = 2,000: (2, 1), after 4,001,996 line ends read

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 brute_force.py

When the loop closes early, A reads about n² line ends, four times as many each time n doubles: about 4 × 10¹⁰ at n = 200,000. B looks at every cell after each filled cell, at least 10⁵ × 10⁶ = 10¹¹ looks at the limits. By the rough budgets of the constraints lesson, that is hours of Python and minutes of C++.

The key idea: a failed union, and a count that moves by one

Links are only ever added, the case union-find is made for.

  • The loop. Feed the lines to a union-find in log order. The first union that returns False joins two substations that earlier lines connected already, so that line closed the loop.
  • Connectivity at any moment. Between two lines, “can power flow from x to y?” is find(x) == find(y), two finds and no search.
  • The islands. Number each cell r · cols + c and keep a list of the land cells. A new land cell is one more island; then union it with each neighbour that is land, and every union that returns True merges two islands into one. A cell that is land already changes nothing.

The same structure also handles links that point one way, links that fail instead of arriving, and spare cables that may be moved, with one change each. Each line and each cell costs a few finds, nearly constant time with union by size and path halving, plus the time to set up the arrays. Redundant edges are the only links whose union fails: in A the first of them is the answer, and in B they are the unions that leave the island count alone.

A dry run of both

The second example of A, with the roots that the two finds return:

Line Roots of its ends union Loop?
(2, 3) 2 and 3 True no
(1, 2) 1 and 2 True no
(4, 5) 4 and 5 True no
(3, 1) 2 and 2 False yes: the answer

The first example of B:

Cell Unions that merged Islands
(0, 0), (0, 2), (2, 1) none: three islands of one cell 1, 2, 3
(0, 1) with (0, 0) and (0, 2) 3 + 1 − 2 = 2
(1, 1) with (0, 1) and (2, 1) 2 + 1 − 2 = 1
(0, 1) land already: skipped 1

Exercise

Exercise · Medium · Python, JavaScript

Islands after each filled cell

A bay is a grid of rows × cols cells, all water at first. A reclamation project fills one cell with land at a time. Write islands_after_each(rows, cols, cells) (islandsAfterEach(rows, cols, cells) in JavaScript): cells lists the filled cells in order as (r, c) pairs, row first, and the function returns one number per cell, the number of islands right after that cell is filled. Land cells that share a side belong to the same island; cells that touch only at a corner do not.

islands_after_each(3, 3, [(0, 0), (0, 2), (2, 1), (0, 1), (1, 1), (0, 1)])   # [1, 2, 3, 2, 1, 1]

The fourth cell joins the two islands of the top row, and the fifth joins that island with the one at the bottom. The last cell is land already: filling it again changes nothing.

  • A cell may be listed more than once.
  • The sample tests include a grid of 1,000 × 1,000 cells with 100,000 filled cells, so counting every island again after each cell is far too slow.
  • Limits: 1 ≤ rows, cols ≤ 1,000 and at most 100,000 cells.

Python · Starter code · islands.py

def islands_after_each(rows, cols, cells):
    """After each filled cell (r, c), the number of islands. One number per cell."""
    # Replace this line with your code.
    return []
The sample tests · test_islands.py
import random
from collections import deque

from islands import islands_after_each


def trusted(rows, cols, cells):
    """The answer the tests trust: after each cell, flood every island of the land again."""
    land, counts = set(), []
    for cell in cells:
        land.add(tuple(cell))
        seen, islands = set(), 0
        for start in land:
            if start in seen:
                continue
            islands += 1
            seen.add(start)
            queue = deque([start])
            while queue:
                r, c = queue.popleft()
                for nxt in ((r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)):
                    if nxt in land and nxt not in seen:
                        seen.add(nxt)
                        queue.append(nxt)
        counts.append(islands)
    return counts


def test_example():
    """the example of the prompt: 1, 2, 3, 2, 1, 1"""
    assert islands_after_each(3, 3, [(0, 0), (0, 2), (2, 1), (0, 1), (1, 1), (0, 1)]) == [1, 2, 3, 2, 1, 1]


def test_no_cells():
    """no cells, no numbers"""
    assert islands_after_each(2, 2, []) == []


def test_refilled_cell():
    """filling a cell that is land already changes nothing"""
    assert islands_after_each(1, 1, [(0, 0), (0, 0), (0, 0)]) == [1, 1, 1]


def test_one_cell_joins_four():
    """the centre of a plus joins four islands at once: 4 becomes 1"""
    assert islands_after_each(3, 3, [(0, 1), (1, 0), (1, 2), (2, 1), (1, 1)]) == [1, 2, 3, 4, 1]


def test_corners_do_not_join():
    """cells that touch only at a corner are separate islands"""
    assert islands_after_each(2, 2, [(0, 0), (1, 1), (0, 1)]) == [1, 2, 1]


def test_rows_do_not_wrap():
    """the end of one row is not next to the start of the next"""
    assert islands_after_each(2, 3, [(0, 2), (1, 0)]) == [1, 2]
    assert islands_after_each(3, 1, [(0, 0), (2, 0), (1, 0)]) == [1, 2, 1]


def test_large_bay():
    """1,000 x 1,000 cells: 50,000 single cells, then the gaps of their rows filled"""
    singles = [(r, c) for r in range(0, 1000, 2) for c in range(0, 200, 2)]
    gaps = [(r, c) for r in range(0, 1000, 2) for c in range(1, 200, 2)]
    counts = islands_after_each(1000, 1000, singles + gaps)
    assert len(counts) == 100_000
    assert counts[49_999] == 50_000
    assert counts[-1] == 500


def test_random_against_recount():
    """300 random bays of up to 5 x 5 cells, checked against a full recount after every cell"""
    rng = random.Random(7)
    for _ in range(300):
        rows, cols = rng.randint(1, 5), rng.randint(1, 5)
        cells = [(rng.randrange(rows), rng.randrange(cols)) for _ in range(rng.randint(0, 20))]
        assert islands_after_each(rows, cols, cells) == trusted(rows, cols, cells), (rows, cols, cells)

JavaScript · Starter code · islands.mjs

/**
 * After each filled cell [r, c], the number of islands. Returns one number per cell.
 * The bay has rows x cols cells, all water at first.
 */
export function islandsAfterEach(rows, cols, cells) {
  // Replace this line with your code.
  return [];
}
The sample tests · islands.test.mjs
import { test, assert } from 'mysmartcopilot:test';
import { islandsAfterEach } from './islands.mjs';

let seed = 7;
const random = () => (seed = (seed * 48271) % 2147483647) / 2147483647;
const randInt = (lo, hi) => lo + Math.floor(random() * (hi - lo + 1));

// The answer the tests trust: after each cell, flood every island of the land again.
function trusted(rows, cols, cells) {
  const land = new Set();
  const counts = [];
  for (const [r, c] of cells) {
    land.add(r * cols + c);
    const seen = new Set();
    let islands = 0;
    for (const start of land) {
      if (seen.has(start)) continue;
      islands += 1;
      seen.add(start);
      const queue = [start];
      for (let head = 0; head < queue.length; head++) {
        const cell = queue[head];
        const y = Math.floor(cell / cols);
        const x = cell % cols;
        for (const [ny, nx] of [[y - 1, x], [y + 1, x], [y, x - 1], [y, x + 1]]) {
          const next = ny * cols + nx;
          if (ny >= 0 && ny < rows && nx >= 0 && nx < cols && land.has(next) && !seen.has(next)) {
            seen.add(next);
            queue.push(next);
          }
        }
      }
    }
    counts.push(islands);
  }
  return counts;
}

test('the example of the prompt: 1, 2, 3, 2, 1, 1', () => {
  assert.deepEqual(islandsAfterEach(3, 3, [[0, 0], [0, 2], [2, 1], [0, 1], [1, 1], [0, 1]]), [1, 2, 3, 2, 1, 1]);
});

test('no cells, no numbers', () => {
  assert.deepEqual(islandsAfterEach(2, 2, []), []);
});

test('filling a cell that is land already changes nothing', () => {
  assert.deepEqual(islandsAfterEach(1, 1, [[0, 0], [0, 0], [0, 0]]), [1, 1, 1]);
});

test('the centre of a plus joins four islands at once: 4 becomes 1', () => {
  assert.deepEqual(islandsAfterEach(3, 3, [[0, 1], [1, 0], [1, 2], [2, 1], [1, 1]]), [1, 2, 3, 4, 1]);
});

test('cells that touch only at a corner are separate islands', () => {
  assert.deepEqual(islandsAfterEach(2, 2, [[0, 0], [1, 1], [0, 1]]), [1, 2, 1]);
});

test('the end of one row is not next to the start of the next', () => {
  assert.deepEqual(islandsAfterEach(2, 3, [[0, 2], [1, 0]]), [1, 2]);
  assert.deepEqual(islandsAfterEach(3, 1, [[0, 0], [2, 0], [1, 0]]), [1, 2, 1]);
});

test('1,000 x 1,000 cells: 50,000 single cells, then the gaps of their rows filled', () => {
  const cells = [];
  for (let r = 0; r < 1000; r += 2) for (let c = 0; c < 200; c += 2) cells.push([r, c]);
  for (let r = 0; r < 1000; r += 2) for (let c = 1; c < 200; c += 2) cells.push([r, c]);
  const counts = islandsAfterEach(1000, 1000, cells);
  assert.equal(counts.length, 100000);
  assert.equal(counts[49999], 50000);
  assert.equal(counts[counts.length - 1], 500);
});

test('300 random bays of up to 5 x 5 cells, checked against a full recount after every cell', () => {
  for (let trial = 0; trial < 300; trial++) {
    const rows = randInt(1, 5);
    const cols = randInt(1, 5);
    const cells = Array.from({ length: randInt(0, 20) }, () => [randInt(0, rows - 1), randInt(0, cols - 1)]);
    assert.deepEqual(islandsAfterEach(rows, cols, cells), trusted(rows, cols, cells), JSON.stringify([rows, cols, cells]));
  }
});
A hint

Give every cell a number, r * cols + c, and make a union-find over all of them, plus a list that says which cells are land. A new land cell is an island of its own until you look at its four neighbours: each neighbour that is land and not yet in the same set is one merge, and every merge leaves one island fewer.

The sample tests run on this device, in your browser (Pyodide, QuickJS): nothing is sent to mysmartcopilot.com. The first run of each language downloads it: Python (about 13.5 MB) or JavaScript (about 0.6 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Python Online Compiler Paste the brute force and your union-find into one file and compare their counts on bays of your own.

Check yourself

4 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 4 While the lines of problem A go into a union-find, union(3, 1) returns False. What does that tell you?

    Choose one answer.

    Show the answer to question 1

    Answer: Substations 3 and 1 were connected already, so this line closes the loop

    union returns False only when both ends already have the same root, which means earlier lines connect them. Adding the line then creates a second route between the two, and that is a loop. It need not repeat an earlier line: in the second example, the line (3, 1) closes the loop 1, 2, 3 that two other lines started.

  2. Question 2 of 4 A cell is filled with land. Three of its four neighbours are land already, and they belong to two different islands. By how much does the number of islands change?

    Type a number.

    Show the answer to question 2

    Answer: -1 islands

    The new cell starts as an island of its own, +1. Of the three unions with its land neighbours, the first one merges it with one island and the second with the other: two unions return True, −2. The third neighbour is in a group the cell has joined already, so its union returns False. In all, 1 − 2 = −1.

  3. Question 3 of 4 In a bay of 4 rows and 5 columns, which number does the cell in row 2, column 3 get, counting rows and columns from 0?

    Type a number.

    Show the answer to question 3

    Answer: 13

    A cell's number is r · cols + c: rows 0 and 1 hold 5 cells each, and column 3 of row 2 comes after 3 more, so 2 · 5 + 3 = 13. Multiplying by the number of rows instead, 2 · 4 + 3 = 11, gives a number that belongs to another cell.

  4. Question 4 of 4 A cell that is land already appears again in the list of filled cells. What should happen to the island count?

    Choose one answer.

    Show the answer to question 4

    Answer: Nothing; the count stays as it was

    The land has not changed, so neither have the islands. Code that skips the check adds one island for the cell and then finds every neighbour in its group already, so no union returns True and the count ends one too high.

Both problems proved, in five languages, and tested Pro: opens with a Pro, Premium or Ultimate pass

A loop of union-find calls is short, but it is right only for a reason. Each solution gets its proof here, then the code in Python, JavaScript, Java, C++ and Go with what each printed, and a comparison with the brute forces on 4,000 random cases.

In this part:

  • Why the first failed union is the line to switch off
  • Why the island count stays right
  • The code in five languages
  • Checked against the brute forces on 4,000 random cases

3 runnable examples (C++, Go, Java, JavaScript, Python) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Islands at scale, and six bugs reproduced Pro: opens with a Pro, Premium or Ultimate pass

The island count has to stay right when a million cells and a hundred thousand fills are involved. This part measures the work of both methods as the bay grows and runs six plausible bugs until each one breaks.

In this part:

  • The work measured: a full recount against union-find
  • Six bugs and the smallest inputs that break them

2 runnable examples (Python) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Questions between links, one-way feeders, failures and spare cables Pro: opens with a Pro, Premium or Ultimate pass

Four problems change one thing about the setting: questions arrive between the links, the links point one way, links fail instead of arriving, or cables may be moved. Each is solved below with the same union-find, and three of them are checked against a brute force.

In this part:

  • Questions between links, answered in nearly constant time
  • One-way feeders: two parents or a loop
  • Lines that fail: walk back in time
  • Spare cables: one move per missing link
  • A practice set with sample answers

1 runnable example (Python) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Interview questions

  1. Fresher to mid · Warm-up

    Land cells are added to a grid one at a time, and a union-find keeps the island count. Why does a new cell change the count by +1, and then by −1 for each union with a land neighbour that returns True?

    A new land cell touches no other land until it is joined to its neighbours, so at first it is an island of its own: +1. Each neighbour that is land belongs to some island. A union with that neighbour returns True only when its island is not yet in the same group as the new cell, and then two islands become one: −1. A union that returns False means the neighbour's island was joined already through another side of the new cell, so nothing changes. A cell between two islands therefore gives +1 − 2 = −1, and the centre of a plus of four islands gives +1 − 4 = −3. A cell that is land already must be skipped before any of this, or it adds an island that no union takes away.

  2. Mid to senior

    A power network is a rooted tree: one main station, and every other station fed by exactly one one-way feeder. Its log of n feeders has one feeder too many. Which feeder do you remove so that the rest is a rooted tree again, taking the one logged last when several would work?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  3. Mid to senior

    A survey grid has 10⁹ × 10⁹ cells, and 200,000 of them become land one at a time. After each, report the number of islands. Arrays of rows × cols entries are out of the question. What do you build, and how much memory and time does it need?

    Model answer, Pro. First step and follow-ups

  4. Fresher to mid

    A lab has n computers joined by m cables, and some computers cannot reach each other. A move unplugs one cable and plugs it in between any two computers. What is the smallest number of moves that connects every computer, or −1 if no number does? Explain why it is the minimum.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • A union that returns False joins items that were connected already; in a growing network, the first one closed the loop.
  • Whether two items are connected at any moment is find(x) == find(y).
  • With cell (r, c) numbered r · cols + c, a new land cell adds one island and each merge with a land neighbour takes one away.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.