LeetCode--547. 朋友圈(java)

并查集

使用场景
组团、配对问题,快速判断两个个体是不是在一个集合中
基本操作

  • makeSet (s):建立一个新的并查集,大小为 s 个元素
  • unionSet(x,y):把元素 x 和 y 所在的集合合并,要求 x 和 y 所在的集合不想交,若相交则不合并
  • find(x):找到 x 所在的集合的代表,该操作可用于判断两个元素是否位于同一个集合,只要将两个代表比较一下即可。

方法1:并查集

  • N个人,每个人都是一个孤立的集合
  • 遍历 M 矩阵,根据 M [ i ][ j ] 是否是 1,进行并查集的合并,若 M [ i ][ j ] = 1,将 i 所处的集合 与 j 所处的集合进行合并
  • 最后查看有多少孤立集合
class Solution {
    public int findCircleNum(int[][] M) {
		UnionFind us = new UnionFind(M.length);
		for(int i = 0;i < M.length;i++) {
			for(int j = 0;j <M[0].length;j++) {
				if(M[i][j] == 1) us.union(i, j);
			}
		}
        return us.count;
	}
}
//创建并查集,作为模板记住即可
class UnionFind{
	int count = 0;//集合的个数
	//parent[i] 表示 i 号集合的代表元素,之后我们就用代表元素区分不同的集合
	int[] parent;
	
	public UnionFind(int n) {//对于 n 个数
		count = n;//每个数都是一个孤立的集合
		parent = new int[n];
		for(int i = 0;i < n;i++) {
			//并查集最常见的初始化的方式
			parent[i] = i;//初始化每个集合的代表元素
		}
	}
	
	public int find(int p) { //给定一个数 p(p 属于 0--n-1),查找它所属的集合的代表元素
		while(p != parent[p]) {
			parent[p] = parent[parent[p]];//p 的爷爷 覆盖 p 的爸爸
			p = parent[p];//指向 爸爸
		}
		return p;
	}
	
	public void union(int p, int q) {
		int rootP = find(p);//找出 p 所在集合的代表元素
		int rootQ = find(q);
		if(rootP == rootQ) return;//说明处于同一个集合
		parent[rootP] = rootQ;
		count--;
	} 
} 

方法2:DFS

	public int findCircleNum(int[][] M) {
		int[] visited = new int[M.length];// visited[i] 表示 i 这个人是否被访问过
		int count = 0;
		for(int i = 0;i < M.length;i++) {
			if(visited[i] == 0) {//i 未被访问过
				dfs(M, visited, i); //探索 i 的朋友圈
				count++;
			}
		}
		return count;
	}
	
	private void dfs(int[][] M, int[] visited, int i) {
		// j 代表其他所有人
		for(int j = 0;j < M.length;j++) {//遍历 i 与其他所有人(包括自己)的朋友关系
			if(M[i][j] == 1 && visited[j] == 0) {
				visited[j] = 1;
				dfs(M, visited, j);
			}
		}
	}
发布了24 篇原创文章 · 获赞 3 · 访问量 540

猜你喜欢

转载自blog.csdn.net/QinLaoDeMaChu/article/details/104023210