Graph · 10 of 43
Making wired Connections
Count how many cables you must unplug and replug so every computer in the office ends up on one network.
- Simple way
- time O(V + E)
room O(V + E) - Clever way
- time O(V + E)
room O(V)
The problem, simply
There are n computers, numbered 0 to n - 1, and a list of cables. Each cable joins two computers. A computer can talk to another if there is a chain of cables between them.
In one move you can unplug any cable and plug it between any two computers. Find the fewest moves so that every computer can talk to every other one. If it can never work, return -1.
A story to remember it
Picture it
Six computers and five cables. Computers 0, 1, 2 and 3 form one group with two cables more than they need. Computers 4 and 5 are alone.
- checking
Examples
A triangle and a loner
- In
n = 4, connections = [[0,1],[0,2],[1,2]]- Out
1
The triangle 0, 1, 2 has one cable too many. Move it to join computer 3.
The picture above
- In
n = 6, connections = [[0,1],[0,2],[0,3],[1,2],[1,3]]- Out
2
Three groups: 3, 4 and 5. Two moves join three groups, and there are two spare cables.
Not enough cable
- In
n = 6, connections = [[0,1],[0,2],[0,3],[1,2]]- Out
-1
Six computers need at least five cables. There are only four, so no amount of moving helps.
One computer
- In
n = 1, connections = []- Out
0
A single computer is already connected to itself.
Way 1: the simple way
Two facts solve it.
- Joining
ncomputers needs at leastn - 1cables. With fewer, return-1. - With enough cables, the spare ones always exist where you need them. So the answer is the number of separate groups minus 1.
Count the groups with breadth first search: start a search from every computer that no search has reached yet, and count the searches.
import java.util.*;
class Solution {
public int makeConnected(int n, int[][] connections) {
if (connections.length < n - 1) return -1; // not enough cable
List<List<Integer>> adj = new ArrayList<>();
for (int i = 0; i < n; i++) adj.add(new ArrayList<>());
for (int[] c : connections) {
adj.get(c[0]).add(c[1]);
adj.get(c[1]).add(c[0]);
}
boolean[] seen = new boolean[n];
int groups = 0;
for (int s = 0; s < n; s++) {
if (seen[s]) continue;
groups++; // a new group starts here
Queue<Integer> line = new ArrayDeque<>();
line.add(s);
seen[s] = true;
while (!line.isEmpty()) {
int u = line.poll();
for (int v : adj.get(u)) {
if (!seen[v]) { seen[v] = true; line.add(v); }
}
}
}
return groups - 1;
}
}How long it takes: every computer and every cable is touched a constant number of times, O(V + E). Extra room: the neighbour lists, O(V + E).
Way 2: the clever way
Same two facts, but count groups with team captains (union find), so we never build neighbour lists. Each computer has a parent; follow parents to reach the group's captain.
- If there are fewer than
n - 1cables, return-1. - Start with
ngroups, each computer its own captain. - For each cable, find the captains of both ends. If they differ, join them and do
groups--. If they are the same, the cable is spare. - Return
groups - 1.
Each cable either joins two groups or is spare
01 / 08
First check: we have 5 cables and 6 computers. Joining 6 computers needs at least 5 cables, and 5 is enough, so an answer exists. Every computer starts as its own group.
- groups
- 6
- spare
- 0
- looking now
- checking
- done
- answer
- rejected
- just added
class Solution {
private int[] parent, rank;
private int find(int x) {
if (parent[x] != x) parent[x] = find(parent[x]); // point straight at the captain
return parent[x];
}
private boolean union(int a, int b) {
int ra = find(a), rb = find(b);
if (ra == rb) return false; // already connected: spare cable
if (rank[ra] < rank[rb]) parent[ra] = rb;
else if (rank[ra] > rank[rb]) parent[rb] = ra;
else { parent[rb] = ra; rank[ra]++; }
return true;
}
public int makeConnected(int n, int[][] connections) {
if (connections.length < n - 1) return -1; // not enough cable
parent = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++) parent[i] = i;
int groups = n;
for (int[] c : connections) {
if (union(c[0], c[1])) groups--;
}
return groups - 1;
}
}How long it takes: each cable costs an almost constant find and union, so about O(V + E). Extra room: only the parent and rank arrays, O(V).
Watch out for
- Why are the spares always enough? A group of
kcomputers withccables hasc - (k - 1)spares. Add that over all groups: total spares =E - (n - groups). IfE >= n - 1, that is at leastgroups - 1. - Returning the number of groups instead of
groups - 1. One group needs zero moves. - Duplicate cables between the same two computers. They are spare, and union find handles them for free.
- Deep recursion in
find. With union by rank the chains stay short, so recursion is safe here.
What interviewers ask next
- Which cables should move? Every cable whose
unionreturned false is spare. Join the captains of the groups one after another using those cables. - Number of provinces or friend circles (LeetCode 547)? The same group counting, without the cable check.
- Cables have different prices and you want the cheapest network? That is a minimum spanning tree: Kruskal's algorithm.
- Can you do it with depth first search? Yes, any search that counts groups works. Union find is handy because it needs no neighbour lists and handles cables arriving one by one.
Remember this
Grown-up words: computers are vertices, cables are edges, groups are connected components, spare cables are redundant edges that close a cycle, team captains are union find roots, and n - 1 is the number of edges in a spanning tree.