1. 程式人生 > 其它 >P37-省份數量-並查集

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]; } }