题目描述
有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。
省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。
给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。
返回矩阵中 省份 的数量。
示例 1:
输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出:2
示例 2:
输入:isConnected = [[1,0,0],[0,1,0],[0,0,1]]
输出:3
代码及其解析
今天刷到这道题的时候,第一时间想到的解法就是使用并查集。我们来先看代码:
class Solution {
public int findCircleNum(int[][] isConnected) {
int cities = isConnected.length;
int[] parent = new int[cities];
for (int i = 0; i < cities; i++) {
parent[i] = i;
}
for (int i = 0; i < cities; i++) {
for (int j = i + 1; j < cities; j++) {
if (isConnected[i][j] == 1) {
union(parent, i, j);
}
}
}
int provinces = 0;
for (int i = 0; i < cities; i++) {
if (parent[i] == i) {
provinces++;
}
}
return provinces;
}
public void union(int[] parent, int index1, int index2) {
parent[find(parent, index1)] = find(parent, index2);
}
public int find(int[] parent,int index){
if(parent[index]!=index){
parent[index]=find(parent,parent[index]);
}
return parent[index];
}
}
原理:
这道题主要用到的思想是并查集,那么什么是并查集,在我看来并查集的思想就是在一个图中将一系列相互连通的节点合并在一起,当成一个整体,最后再算出一共有多少个这样的整体。
那么是如何实现的呢?我们以这道题为例。
这道题中用一个二维数组isConnected[i][j] = 1 来表示第 i 个城市和第 j 个城市直接相连。
多个相连的城市算作一个省份,问一共有多少个省份。
这道题的关键在于如何将相连的城市进行合并?
题解中采用的方法为用一个数组parent来表示该节点的根节点,例如用parent[i]的值表示第i个节点的根节点。parent[0]=0,parent[1]=0,就代表第一个节点的根节点为它本身,第二个节点的根节点的是第一个节点,即代表两个节点相连了。
在最开始我们先初始化所有的节点,将它的根节点设为其本身,再遍历整个二维数组,将二维数组中包含的节点进行合并,即函数union()。
public void union(int[] parent, int index1, int index2) {
parent[find(parent, index1)] = find(parent, index2);
}
在该方法中用了另一个find方法,这个find的方法就是为了寻找一个节点的根节点。union方法中将第二个节点的根节点变为了第一个节点的根节点,这样就完成了合并。
find方法中找寻根节点时利用了递归,在方法中如果这个节点的根节点不是其本身,那就递归一次,直到这个节点的根节点是其本身为止,在返回。
假如在前面的合并动作中,先将第一个节点和第二个节点合并了,然后想再合并第三个节点,也就是parent[0]=0,parent[1]=0,parent[2]=1,那么在寻找下标为2也就是第三个节点时就会通过递归将parent[2]的值设为parent[1]的值,也就是0,这样就找到了第三个节点的根节点。
因为每次合并时都是重新设置parent数组中的值,因此当多个节点进行合并,每次都能快速地找到根节点并重新设置,所以时间复杂度可以达到O(1).
通过以上方法将数组合并完成后,遍历一遍parent数组,如果某节点地根节点是其本身,就证明这是一个整体,是一个省份,这样我们就可以找到所有地省份数了。
该题的关键在于理解理解find方法,理解是如何找到根节点并进行合并的。