今天写了一道力扣题,547. 省份数量,第一眼没看懂,总觉得一个省之间不相连也可以的,看了下例题后立刻想到了考试前学过的并查集,用在这道题上最为合适了。
题目是这样的,给定方阵,若某点值为1,则点下标代表的i,j两城市相连接,如果是相邻的城市为同一个省,具有那种等量替换的性质,(a==b,b==c则a==c的),最终让算几个省份,这不就是把相同省份的城市分为了一个集合中,最后计算有多少个集合的问题了吗。
有一句话说的好,我们由和周围的人和社会关系组成,对于每一个个体,在不产生社会关系前都是独立的个体,所以我们属于自己。这个方法也一样,在没形成关系之前,我们都是属于我们自己的。所以有
for (int i = 1; i <=(个体数量); i++) {
father[i]=i;//每一个结点的父节点都是自己
}
产生联系:
当两个点产生联系时候,就对这两个点合并。
public static void unoin(int a,int b){
father[findfather(a)]=findfather(b);
}
public static int findfather(int a){
if(a==father[a]){
return a;
}
father[a]=findfather(father[a]);
return father[a];
}
这两个方法的作用就是把两个结点合并起来的关键。
对于每个结点来说,他属于一个集合内,这个集合总有一个父节点,这个父节点是真正的父节点,是这个集合的”创始人“,投靠门派,就找老大,就找这个创始人,所以有了,如果没找到a!=father[a]就一直递归的找,直到找到为止。然后将这个集合的根节点加入新集合,则合并成功。
father[findfather(a)]=findfather(b);
最后对 判断几个老大即可,(剩下的小弟点都归并到老大这里了)。
int count=0;
for (int i =1; i <=n*m; i++) {
if(findfather(i)==i){
count++;
}
}
完整代码:
public static int findCircleNum(int[][] isConnected) {
int citynum=isConnected.length;
int []father=new int[isConnected.length];//记录每一个结点的父节点 最后也只需要 判断有几个父亲 就是几个省份
for (int i = 0; i < father.length; i++) {
father[i]=i;
}
//遍历相连的结点 归并为一组
for (int i = 0; i < isConnected.length; i++) {
for (int j = 0; j < isConnected.length; j++) {
if(isConnected[i][j]==1){
//如果相连 归并
hebing(father,i,j);
}
}
}
int num=0;
for (int i = 0; i <citynum ; i++) {
if(find(i,father)==i){
num++;
}
}
return num;
}
public static void hebing(int []father,int i,int j){
father[find(i,father)]=find(j,father);
}
public static int find(int i,int []father){
if(father[i]!=i){
father[i]=find(father[i],father);
}
return father[i];
}
这样的题有很多种,像以前写的找冰岛数量,判断两个人是不是亲戚之类都是这样思想。
并查集的模板基本上是这样,小的细节需要自己进行判断。
今天郑州的风有点大,早上十点才起床,这几天的气温又下去了,按说往年5.1气温都该热起来了,但今年这时候又穿起来外套了,昨天是微信小程序答辩,感觉没学多少东西关于小程序,这些新技术有时候感觉学了不是很有用,因为这些东西的原理都被封装起来了,底层的逻辑看不到,用久了很难提升,另外感觉小程序这个东西很潦草,这个开发者工具的软件也是。倒不如多学点计算机系统,原理这些。学校栅栏的花开了,昨晚打电话的时候看到的,很漂亮,不艳,不俗。晚香浮处,见蔷薇半吐。花花草草,这些都是生活中的情趣。