基本算法学习--并查集记录(有固定的解题模板)

(一)理论学习:

https://blog.csdn.net/dm_vincent/article/details/7655764

文中对并查集进行了理论说明和常用的建模方法,以及解决思路即:Quick-Find 算法, Quick-Union 算法

将所有的节点以整数表示,即对N个节点使用0到N-1的整数表示。而在处理输入的Pair之前,每个节点必然都是孤立的,即他们分属于不同的组,可以使用数组来表示这一层关系,数组的index是节点的整数表示,而相应的值就是该节点的组号了。该数组可以初始化为:

for(int i = 0; i < size; i++)
    id[i] = i; 

Quick-Find算法会造成牵一发而动全身;Quick-Union算法通过树将节点组织起来,涉及到极端情况下的复杂度,在进行合并过程中将树的高度考虑在内,即小的树合并到大的树上,避免出现线性表的极端情况,因此引入Weighted Quick-Union方法。下文解题主要用该方法进行。

文中列举的几种方法的复杂度:

基本算法学习--并查集记录(有固定的解题模板)

(二)解题模板 基本算法学习--并查集记录(有固定的解题模板)

(三)Leetcode刷题记录:

已通过 #1319

连通网络的操作次数

48.2% 中等  
已通过 #547

朋友圈

56.4% 中等  
已通过 #684

冗余连接

58.1% 中等  
已通过 #200

岛屿数量

49.4% 中等  

其中岛屿数量,同样可以套用算法模型,相同的UF,union,find,关键看connected的实现,记录属于哪个子类,二维数组用一维表示。

解决JAVA实现:

int [] sz;
int [] father;

public void initUF(int n) {
    sz = new int[n];
    father = new int[n];
    for (int i = 0; i < n; i++) {
        sz[i] = 1;
        father[i] = i;
    }
}

public int find(int p) {
    if (p != father[p]) {
        p = find(father[p]);
    }
    return p;
}

public void union(int p, int q) {
    int i = find(p);
    int j = find(q);
    if (i == j) return;
    if (sz[i] > sz[j]) {
        sz[i] += sz[j];
        father[i] = j;
    } else {
        sz[j] += sz[i];
        father[j] = i;
    }
}

public int numIslands(char[][] grid) {
    int n = grid.length;
    int m = grid[0].length;
    int k = m * n;
    initUF(k);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            int t1 = i*m+j;
            int t2 = t1 + 1;
            int t3 = t1 + m;
            if (grid[i][j] == '1' && j+1<m && grid[i][j+1] == '1') {
                union(t1, t2);
            }
            if (grid[i][j] == '1' && i+1<n && grid[i+1][j] == '1') {
                union(t1, t3);
            }
        }
    }

    int num = 0;
    for (int i = 0; i < k; i++) {
        if (grid[i/m][i%m] == '1' && father[i] == i) {
            num++;
        }
    }
    return num;
}