【启发】leetcode -- 547. Friend Circles【并查集 + 集合标识更新的时机】

2024-03-29 06:18

本文主要是介绍【启发】leetcode -- 547. Friend Circles【并查集 + 集合标识更新的时机】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目

There are N students in a class. Some of them are friends, while some are not. Their friendship is transitive in nature. For example, if A is a direct friend of B, and B is a direct friend of C, then A is an indirect friend of C. And we defined a friend circle is a group of students who are direct or indirect friends.

Given a N*N matrix M representing the friend relationship between students in the class. If M[i][j] = 1, then the ith and jth students are direct friends with each other, otherwise not. And you have to output the total number of friend circles among all the students.

Example 1:

Input: 
[[1,1,0],[1,1,0],[0,0,1]]
Output: 2
Explanation:The 0th and 1st students are direct friends, so they are in a friend circle. 
The 2nd student himself is in a friend circle. So return 2.

Example 2:

Input: 
[[1,1,0],[1,1,1],[0,1,1]]
Output: 1
Explanation:The 0th and 1st students are direct friends, the 1st and 2nd students are direct friends, 
so the 0th and 2nd students are indirect friends. All of them are in the same friend circle, so return 1.

Note:

  1. N is in range [1,200].
  2. M[i][i] = 1 for all students.
  3. If M[i][j] = 1, then M[j][i] = 1.

题意概述

给定一个矩阵N*N ,表示N个人之间的朋友关系。朋友关系具有传递性,试找出这N个人中有多少个朋友团体。

分析及解答

解法1:(简明、清晰)
  • 未进行路径压缩
  • 参考:(https://discuss.leetcode.com/topic/85039/java-solution-union-find)
   public int findCircleNum(int[][] M) {int m = M.length, cnt = 0;int[] root = new int[m]; for (int i = 0; i < m; i++) root[i] = i; for (int i = 0; i < m; i++) for (int j = i + 1; j < m; j++)if (M[i][j] == 1) unionFind(root, i, j);for (int i = 0; i < m; i++)if (i == root[i]) cnt++;return cnt;}void unionFind (int[] root, int v1, int v2) {while (root[v1] != v1) v1 = root[v1]; //find v1's rootwhile (root[v2] != v2) v2 = root[v2]; //find v2's rootif (root[v1] != root[v2]) root[v2] = v1; //unite the 2 subtrees }



解法2:(我的丑的版本
  • 注意:发现新的朋友关系之后的影响】当在遍历过程中发现新的朋友关系时,我们不仅仅需要考虑其对于当下正在处理的朋友关系的影响,同时还要考虑对于过去已经建立的朋友关系的影响(可能会连接起以前独立的两个朋友团体)。(易忽略

class Solution {public static int findCircleNum(int[][] M) {if(M == null || M.length == 0){return 0;}int[] friends =  new int[M.length];for(int i = 0; i < friends.length;i++){friends[i] = -1; // -1 表示尚未分配集合。}for(int i = 0; i < M.length; i++){for(int j = i ; j < M.length;j++){//【关键】初始化 朋友关系。(注意遍历次序:自上而下,自左向右)(一个集合中最小的数作为集合的标志)//只有发现存在朋友关系时,才进行相应的处理。if(M[i][j] == 1){//若之前并未分配集合,首次分配集合。if(friends[j] == -1){friends[j] = i;}else{//若j之前已经分配了集合。则需要进一步传递这种朋友关系。int newRoot = find(friends, j);//因为i中可能有自己的集合标志。而与 j的朋友关系,将这两个集合关联了起来,形成一个集合。所以,//我们将其中一个集合的根标记为另一个集合的根。friends[friends[i]] = newRoot;//将i的根标记为新的集合的根。friends[i] = newRoot;}}}}int result = 0;for(int i = 0; i < friends.length; i++){//每个 i = friends[i]的人,都代表着一个朋友团体。if(i == friends[i]){result ++;}}return result;}public static int find(int[] friends,int i){//查找 i 所属于的集合的根(集合的标志)。while(i != friends[i]){i = friends[i];}return i;}
}


这篇关于【启发】leetcode -- 547. Friend Circles【并查集 + 集合标识更新的时机】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/857831

相关文章

Ubuntu 24.04 LTS怎么关闭 Ubuntu Pro 更新提示弹窗?

《Ubuntu24.04LTS怎么关闭UbuntuPro更新提示弹窗?》Ubuntu每次开机都会弹窗提示安全更新,设置里最多只能取消自动下载,自动更新,但无法做到直接让自动更新的弹窗不出现,... 如果你正在使用 Ubuntu 24.04 LTS,可能会注意到——在使用「软件更新器」或运行 APT 命令时,

基于Redis有序集合实现滑动窗口限流的步骤

《基于Redis有序集合实现滑动窗口限流的步骤》滑动窗口算法是一种基于时间窗口的限流算法,通过动态地滑动窗口,可以动态调整限流的速率,Redis有序集合可以用来实现滑动窗口限流,本文介绍基于Redis... 滑动窗口算法是一种基于时间窗口的限流算法,它将时间划分为若干个固定大小的窗口,每个窗口内记录了该时间

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

hdu1689(线段树成段更新)

两种操作:1、set区间[a,b]上数字为v;2、查询[ 1 , n ]上的sum 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdl

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

AI行业应用(不定期更新)

ChatPDF 可以让你上传一个 PDF 文件,然后针对这个 PDF 进行小结和提问。你可以把各种各样你要研究的分析报告交给它,快速获取到想要知道的信息。https://www.chatpdf.com/

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

poj 1182 并查集 食物链类

题意: 有n只动物,分别编号1....n。所有动物都属于A,B,C中的一种,已知A吃B,B吃C,C吃A。 按顺序给出下面两种共K条信息: 1. x 和 y 属于同一类。 2. x 吃 y 。 然而这些信息可能会出错,有可能有的信息和之前给出的信息矛盾,也有的信息可能给出的 x 和 y 不在n的范围内。 求k条信息中有多少条是不正确的。 解析: 对于每只动物,创建3个元素 i