【启发】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

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Redis中的有序集合zset从使用到原理分析

《Redis中的有序集合zset从使用到原理分析》Redis有序集合(zset)是字符串与分值的有序映射,通过跳跃表和哈希表结合实现高效有序性管理,适用于排行榜、延迟队列等场景,其时间复杂度低,内存占... 目录开篇:排行榜背后的秘密一、zset的基本使用1.1 常用命令1.2 Java客户端示例二、zse

Java集合之Iterator迭代器实现代码解析

《Java集合之Iterator迭代器实现代码解析》迭代器Iterator是Java集合框架中的一个核心接口,位于java.util包下,它定义了一种标准的元素访问机制,为各种集合类型提供了一种统一的... 目录一、什么是Iterator二、Iterator的核心方法三、基本使用示例四、Iterator的工

Java JUC并发集合详解之线程安全容器完全攻略

《JavaJUC并发集合详解之线程安全容器完全攻略》Java通过java.util.concurrent(JUC)包提供了一整套线程安全的并发容器,它们不仅是简单的同步包装,更是基于精妙并发算法构建... 目录一、为什么需要JUC并发集合?二、核心并发集合分类与详解三、选型指南:如何选择合适的并发容器?在多

python语言中的常用容器(集合)示例详解

《python语言中的常用容器(集合)示例详解》Python集合是一种无序且不重复的数据容器,它可以存储任意类型的对象,包括数字、字符串、元组等,下面:本文主要介绍python语言中常用容器(集合... 目录1.核心内置容器1. 列表2. 元组3. 集合4. 冻结集合5. 字典2.collections模块

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

MySQL 数据库表操作完全指南:创建、读取、更新与删除实战

《MySQL数据库表操作完全指南:创建、读取、更新与删除实战》本文系统讲解MySQL表的增删查改(CURD)操作,涵盖创建、更新、查询、删除及插入查询结果,也是贯穿各类项目开发全流程的基础数据交互原... 目录mysql系列前言一、Create(创建)并插入数据1.1 单行数据 + 全列插入1.2 多行数据

Java集合中的链表与结构详解

《Java集合中的链表与结构详解》链表是一种物理存储结构上非连续的存储结构,数据元素的逻辑顺序的通过链表中的引用链接次序实现,文章对比ArrayList与LinkedList的结构差异,详细讲解了链表... 目录一、链表概念与结构二、当向单链表的实现2.1 准备工作2.2 初始化链表2.3 打印数据、链表长

linux安装、更新、卸载anaconda实践

《linux安装、更新、卸载anaconda实践》Anaconda是基于conda的科学计算环境,集成1400+包及依赖,安装需下载脚本、接受协议、设置路径、配置环境变量,更新与卸载通过conda命令... 目录随意找一个目录下载安装脚本检查许可证协议,ENTER就可以安装完毕之后激活anaconda安装更

Nginx进行平滑升级的实战指南(不中断服务版本更新)

《Nginx进行平滑升级的实战指南(不中断服务版本更新)》Nginx的平滑升级(也称为热升级)是一种在不停止服务的情况下更新Nginx版本或添加模块的方法,这种升级方式确保了服务的高可用性,避免了因升... 目录一.下载并编译新版Nginx1.下载解压2.编译二.替换可执行文件,并平滑升级1.替换可执行文件