P37-省份数量-并查集
//省份数量 /* * 有n个城市,其中一些彼此相连,另一些没有相连。如果城市a与城市b直接相连,且城市b与城市c直接相连, * 那么城市a与城市c间接相连 * 省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。 * 给你一个 n * n 的矩阵 isConnected,其中isConnected[i][j]=1表示第i个城市和第j个城市直接相连, * 而isConnected[i][j]=0表示二者不直接相连 * 返回矩阵中省份(直接或间接相连的是一个省,没有关联的是另一个省)的数量 * */ public class P37 { public static void main(String[] args) { System.out.println(getProvince(new int[][]{{1,1,0},{1,1,0},{0,0,1}})); //2 System.out.println(getProvince(new int[][]{{1,0,0},{0,1,0},{0,0,1}})); //3 } //并查集,并是合并两个树,查是查根节点,直到该合并的都合并了,树和树之间再没办法合并,题目就解开了 //合并的时候,是以树高度大的作为根节点,可以减少维护所有节点指向新节点的次数,并且合并后高度还是不变 //思路:一个一维数组代表城市,不同下标就是不同城市,数组的值是root节点的下标,最后统计这个数组有多少不同的root,就是多少个省 //直接统计不太好,还可以是 数组下标 == 数组值,就是一个省 //并查集 private static int getProvince(int[][] citiesConnected) { int cities = citiesConnected.length; //初始假设每一个城市都是一个省 int[] head = new int[cities]; int[] level = new int[cities]; //维护层高,用来减少维护head数组的。 // 合并的时候,层高相同时,值都加1 // 层高不同时,小的变为大的值 for (int i=0; i<cities; i++){ head[i] = i; //初始化 level[i] = 1; } for(int i=0; i<cities; i++){ for(int j=i+1; j<cities; j++){ if(citiesConnected[i][j] == 1){ //属于同一个省,合并 merge(i, j, head, level); } } } //统计省份数量 int provinces = 0; for(int i=0; i<cities; i++){ if(head[i] == i){ provinces++; } } return provinces; } //合并方法 static void merge(int x, int y, int[] head, int[] level){ int i = find(x, head); //找x的根节点 int j = find(y, head); //找y的根节点 if(i == j){ //代表同一个树 return; } //不是同一个树 if(level[i] <= level[j]){ //合并,矮的合到高的上 head[i] = j; //i的level要++ }else{ head[j] = i; //j的level要++ } if(level[i] == level[j]){ level[i]++; //比较准确的是把这个判断放在上面,看是i还是j++,不过其实都++并不影响结果,不影响level[i] <= level[j]判断结果 level[j]++; } } //找根节点 //如【0,1,1,2,3】,这样root共有2个,分别是0和1索引,但假如4号索引要找根节点,需要递归,直到找到值等于下标的值 private static int find(int x, int[] head) { if(head[x] == x){ return x; } head[x] = find(head[x], head); //还要维护指针,这样下次就不用再次递归找root(head)了 //[0,1,1,2,1] return head[x]; } }