本题的关键是要知道图论中的一个原理:无向图中, n个结点 至少需要 n-1条边,才能使各个结点相连。
有两种解法:
1.用递归遍历的方式,计算有多少个独立的连通的部分,我称为“簇”。需要移动的边就是 簇的个数减1。
2.使用并查集,计算有几个联通部分,有几条多余的边。如果多余的边小于联通部分,返回-1。否则返回簇的个数减1。
class Solution { Map<Integer, List<Integer>> graph = new HashMap<>(); boolean[] visited; public int makeConnected(int n, int[][] connections) { if(connections.length < n-1) return -1; for(int[] edge: connections){ graph.putIfAbsent(edge[0], new ArrayList<>()); graph.putIfAbsent(edge[1], new ArrayList<>()); graph.get(edge[0]).add(edge[1]); graph.get(edge[1]).add(edge[0]); } // true代表已经访问过,false代表未访问 visited = new boolean[n]; int count = 0; for(int i = 0; i < n; i++){ if(!visited[i]&& dfs(i)) count++; } return count-1; } public boolean dfs(int cur){ if(visited[cur]) return true; if(!graph.containsKey(cur)) return true; visited[cur] = true; for(int next: graph.get(cur)){ if(!visited[next]) dfs(next); } return true; } }
class Solution { public int makeConnected(int n, int[][] connections) { int[] parent = new int[n]; for(int i = 0; i < n; i++){ parent[i] = i; } int extraEdge = 0; int count = 0; for(int[] edge:connections){ int p = findParent(parent, edge[0]); int q = findParent(parent, edge[1]); if(p == q) extraEdge++; //有公共祖先,说明此条边多余,可以去掉 else parent[q] = p; //如果没有,根据connections矩阵,将两个点连接起来 } for(int i = 0; i < n; i++){ if(parent[i] == i) count++; //计算有多少个祖先,即多少个 单独的联通量 } return (extraEdge >= count-1) ? count-1 : -1; } public int findParent(int[] parent, int x){ while(parent[x] != x){ x = parent[x]; } return x; } }