题目
https://leetcode-cn.com/problems/number-of-operations-to-make-network-connected/solution/lian-tong-wang-luo-de-cao-zuo-ci-shu-by-leetcode-s/
解法
连接n台电脑则至少需要n - 1条边,如果边数小于n - 1 则直接返回-1。如果m条边组成的图中恰好有一个连通分量说明n台电脑是连通的,如果有多个连通分量则说明边集中有些边是多余的,由于边集大于等于n-1,需要移动边数为连通分量数 - 1,肯定存在多余的边能将网络连通。
深度优先搜索
class Solution {
public int makeConnected(int n, int[][] connections) {
if (connections.length < n - 1) return -1;
List<Integer>[] adjs = new List[n];
for (int i = 0; i < n; i++) {
adjs[i] = new ArrayList<>();
}
for (int[] c : connections) {
int a = c[0];
int b = c[1];
adjs[a].add(b);
adjs[b].add(a);
}
int counter = 0;
boolean[] visited = new boolean[n];
for (int i = 0; i < n; i++) {
if (!visited[i]) {
dfs(adjs, visited, i);
counter++;
}
}
return counter - 1;
}
// 必须传入整个邻接表
private void dfs(List<Integer>[] adjs, boolean[] visited, int v) {
visited[v] = true;
for (Integer a : adjs[v]) {
if (!visited[a]) {
dfs(adjs, visited, a);
}
}
}
}
并查集
class Solution {
public int makeConnected(int n, int[][] connections) {
if (connections.length < n - 1) return -1;
UnionFind uf = new UnionFind(n);
for (int[] c : connections) {
uf.union(c[0], c[1]);
}
return uf.getCounter() - 1;
}
private class UnionFind {
private int[] parent;
private int[] rank;// 以当前节点为根节点的子树的节点数
private int counter;
public UnionFind(int n) {
parent = new int[n];
rank = new int[n];
counter = n;
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = 1;
}
}
public int find(int x) {
while (x != parent[x]) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX == rootY) return;
if (rank[rootX] > rank[rootY]) {
int temp = rootX;
rootX = rootY;
rootY = temp;
}
parent[rootX] = rootY;
rank[rootY] += rank[rootX];
counter--;
}
public int getCounter() {
return counter;
}
}
}