【LeetCode】LeetCode 547. 省份数量(Java版 什么是并查集)

427ef4152dbf4b6c92618a198935cb6c.png

  📝个人主页:哈__

期待您的关注 

1b7335aca73b41609b7f05d1d366f476.gif

一、题目描述

 

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。

省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。

给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。

返回矩阵中 省份 的数量。

06fb37df43c1402bac08cb1b3a8644e7.png

a3569267761647129e2c156a424fc7dd.png 

二、思路讲解 

这是一道有关图的算法题目,题目当中给出了这样的描述:共有n个城市,其中的一些彼此相连,一些没有连接,如果a与b相连并且b与c相连,那么a与c也相连,这不就是连通性嘛。在看看这道题让求的是什么,求的是省份的数量,而一个省份内的地点之间都是连通的,题目让我们返回省份的值。我们的目标就是把每一个地区分到一个省份当中。

在这里我要给大家先讲解一种概念“并查集”。

什么是并查集?在我看来就是将图中的结点进行分类的操作,“并”就是将两个结点分类到一起,“查”就是查找结点到底是属于哪个类的。

这样子的描述不够清晰,我引入这样的一个例子。

我在以前看电视剧的时候,总是会有双方交战的场景,我当时就在想,他们的双方是如何分清谁是谁的,难道不会打错人吗?青青草原的绿草已经被羊羊们吃光了,羊羊们为了争夺资源开始了内战,在某一天喜羊羊带领着“喜门”大军去占领一片新的草原,沸羊羊带领着“沸门”大军也去争夺这片草原。两军在小路交叉口遇见。

7bbfa7b329e64112a52c8f06c2f3f152.png

 这次对决的双方羊数很多,假定羊都是白色的,无法区分,我们强制在两只羊交战之前都要自报家门,如果这两只羊是一个阵营的那么就不交战,那么该如何自报家门呢?乐羊羊问道:“你是哪一个阵营的,你阵营的首领是谁”。哈羊羊说道:“我是喜门的,我的首领是谁我忘了,不过我知道我的上层是谁,让我问问我的上层首领是谁”。于是哈羊羊问了他的上层,他的上层又问了上层,最后通知到了喜羊羊这里,喜羊羊又往下通报确认哈羊羊的身份,最后乐羊羊确认了哈羊羊的身份,并且把哈羊羊当作是自己人。

61e4c19474f04a8a958f04c7b53ef728.png

 喜羊羊和沸羊羊大战一场,突然一条情报传入到他们的耳中:“报告门主,美门门主美羊羊被灰太狼抓走了,请求支援!”喜羊羊和沸羊羊一听,立感不妙,现在不是内战的时候,要去救援美羊羊,为了防止内战,于是两羊商量,决定选出一羊作为另一只羊的上层,这样喜门和沸门就完成了合并过程,双方的羊在交战前再次询问上层的时候,都会是喜羊羊或者沸羊羊。

这就是一个简单的“查”和“并”的过程。并查集的关键就是这两个过程。

定义以下的find函数。p是一个数组,用于记录每一个人的上层是谁。当一个人的上层就是自己的时候,那这个人就是门派老大。

int find(int x){
    while(p[x] != x){
       x = p[x];
    }
  return x;
}

定义以下的join函数,用于将两个元素归为一类。 

void join(int x,int y){
    int fx=find(x), fy=find(y);    //喜门1羊的老大是喜羊羊   沸门1号的老大是沸羊羊
    if(fx != fy)                // 如果他们的老大不同
        p[fx]=fy;            //把喜门1号的老大的老大改为沸羊羊 也就是喜羊羊的老大改为沸羊羊
}

 现在我们来解答题目。

class Solution {
    public int [] p = new int[201];
    public int find(int x){
       while(p[x] != x){
       x = p[x];
        }
    return x;
    }
    public void join(int x,int y){
        int px = find(x);
        int py = find(y);
        if(px != py){
            p[px] = py;
        }
    }
    public int findCircleNum(int[][] isConnected) {
        int m = isConnected.length;
        int n = isConnected[0].length;
        for(int i = 0;i<p.length;i++){
            p[i] = i;
        }
        for(int i = 0;i<m;i++){
            for(int j = 0;j<n;j++){
                if(isConnected[i][j] == 1 && i != j){
                    join(i,j);
                }
            }
        }
        HashSet<Integer> set = new HashSet<>();
        for(int i = 0;i<m;i++){
            set.add(find(p[i]));
        }
        return set.size();
    }
}

上边用到了HashSet结构,HashSet结构不允许有重复值,对于我们的p数组,我们去查找每一个人的门主是谁然后把门主添加到set中,最后进行一个去重,剩下来的就是门主的个数,他们无法合并到一起。对于题目来说就是省份的个数。题目中只有connected为1的两个城市,我们进行join操作。

 

a9b099741c154a1abd45c9edefef79c4.png

可见效率有多低。 

三、优化find方法

我们之前的找老大的方法是层层向上,但是想一想,一个门派的所有老大只有一个人,如果我们把每个人的上层都改为门主的话,是不是就十分的方便了呢?

int find(int x){
    //如果x的上层不是门主,那么就接着查找这个人上层的老大
    if(p[x] != x) p[x] = find(p[x]); //查找老大的时候顺便将这个人的上层的老大修改为门主
    return p[x];
}

 再来看看结果。

f496c34bad914ae59840d17d40239de4.png

 代码。

class Solution {
    public int [] p = new int[201];
    public int find(int x){
       if(p[x] != x) p[x] = find(p[x]); //查找老大的时候顺便将这个人的上层的老大全部修改为门主
        return p[x];
    }
    public void join(int x,int y){
        int px = find(x);
        int py = find(y);
        if(px != py){
            p[px] = py;
        }
    }
    public int findCircleNum(int[][] isConnected) {
        int m = isConnected.length;
        int n = isConnected[0].length;
        for(int i = 0;i<p.length;i++){
            p[i] = i;
        }
        for(int i = 0;i<m;i++){
            for(int j = 0;j<n;j++){
                if(isConnected[i][j] == 1 && i != j){
                    join(i,j);
                }
            }
        }
        HashSet<Integer> set = new HashSet<>();
        for(int i = 0;i<m;i++){
            set.add(find(p[i]));
        }
        return set.size();
    }
}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/498713.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

位操作符

简介&#xff1a; &&#xff0c;|,^,~都是常见的位操作符&#xff0c;操作对象是二进制数&#xff0c;运算时须将原码转换成补码&#xff08;符号位为0&#xff0c;即正数时&#xff0c;补码与原码一致&#xff0c;不需要再转换&#xff09;&#xff0c;位数不一致时&#…

ros2相关代码记录

1.ros2概述 ROS2&#xff08;Robot Operating System 2&#xff09;是一个用于机器人应用程序的开源软件框架。它是ROS&#xff08;Robot Operating System&#xff09;的下一代版本&#xff0c;旨在改进和扩展原始ROS的特性&#xff0c;以适应更广泛的机器人应用场景和需求。…

HarmonyOS入门--配置环境 + IDE汉化

文章目录 下载安装DevEco Studio配置环境先认识DevEco Studio界面工程目录工程级目录模块级目录 app.json5module.json5main_pages.json通知栏预览区 运行模拟器IED汉化 下载安装DevEco Studio 去官网下载DevEco Studio完了安装 配置环境 打开已安装的DevEco Studio快捷方式…

【机器学习】数据探索(Data Exploration)---数据质量和数据特征分析

一、引言 在机器学习项目中&#xff0c;数据探索是至关重要的一步。它不仅是模型构建的基础&#xff0c;还是确保模型性能稳定、预测准确的关键。数据探索的过程中&#xff0c;数据质量和数据特征分析占据了核心地位。数据质量直接关系到模型能否从数据中提取有效信息&#xff…

Day24:私信列表、私信详情、发送私信

测试用户&#xff1a;用户名aaa 密码aaa 查询当前用户的会话列表&#xff1b;每个会话只显示一条最新的私信&#xff1b;支持分页显示。 首先看下表结构&#xff1a; conversation_id: 用from_id和to_id拼接&#xff0c;小的放前面去&#xff08;因为两个人的对话应该在一个会…

Linux:详解TCP报头类型

文章目录 温习序号的意义序号和确认序号报文的类型 TCP报头类型详解ACK: 确认号是否有效SYN: 请求建立连接; 我们把携带SYN标识的称为同步报文段FIN: 通知对方, 本端要关闭了PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走RST: 对方要求重新建立连接; 我们把携带RST标识的称…

【学习】软件企业何时会选择第三方软件测试机构

近年来&#xff0c;随着软件行业的迅猛发展&#xff0c;软件企业对软件测试的需求也越来越大。为了保证软件的质量和稳定性&#xff0c;许多企业选择寻找第三方软件测试机构来进行软件测试。第三方软件测试机构是独立于软开发企业的专业机构&#xff0c;主要从事软件测试和质量…

【SpringBoot从入门到精通】02_SpringBoot快速上手

二、SpringBoot快速上手 环境准备&#xff1a; Java8及以上 Maven3.5 https://docs.spring.io/spring-boot/docs/2.7.14/reference/html/getting-started.html#getting-started SpringBoot 2.x 最新版 开发工具&#xff1a; IDEA 2022 2.1 开发第一个SpringBoot应用程序 …

什么是土壤墒情检测站?它在农业生产中有什么作用?

土壤墒情检测站是一种专门用于监测土壤水分状况和土壤水力性质的设备。它由多个传感器和数据采集单元组成&#xff0c;能够实时监测土壤中的水分含量、土壤温度等参数&#xff0c;并收集和记录相关的数据&#xff0c;提供土壤墒情&#xff08;即土壤水分状态&#xff09;的详细…

|行业洞察·趋势报告|《2024旅游度假市场简析报告-17页》

报告的主要内容解读&#xff1a; 居民收入提高推动旅游业发展&#xff1a;报告指出&#xff0c;随着人均GDP的提升&#xff0c;居民的消费能力增强&#xff0c;旅游需求从传统的观光游向休闲、度假游转变&#xff0c;国内人均旅游消费持续增加。 政府政策促进旅游市场复苏&…

代码随想录——移除元素(Leetcode27)

题目链接 暴力&#xff1a;&#xff08;没有改变元素相对位置&#xff09; class Solution {public int removeElement(int[] nums, int val) {int len nums.length;for(int i 0; i < len; i){if(nums[i] val){for(int j i 1; j < len; j){nums[j-1] nums[j];}i…

C#自定义最大化、最小化和关闭按钮

目录 1.资源文件 2.读取资源文件中的图片 3.WindowState属性 4. 示例 用户在制作应用程序时&#xff0c;为了使用户界面更加美观&#xff0c;一般都自己设计窗体的外观&#xff0c;以及窗体的最大化、最小化和关闭按钮。本例通过资源文件来存储窗体的外观&#xff0c;以及最…

【设计模式】中介者模式的应用

文章目录 1.概述2.中介者模式的适用场景2.1.用户界面事件2.2.分布式架构多模块通信 3.总结 1.概述 中介者模式&#xff08;Mediator Pattern&#xff09;是一种行为型设计模式&#xff0c;它用于解决对象间复杂、过度耦合的问题。当多个对象&#xff08;一般是两个以上的对象&…

腾讯云邮件推送功能有哪些?如何有效使用?

腾讯云邮件推送如何设置&#xff1f;怎么用邮件推送做高效营销&#xff1f; 腾讯云作为业界领先的云服务提供商&#xff0c;其邮件推送功能在便捷性、稳定性和安全性上都有着出色的表现。那么&#xff0c;腾讯云邮件推送功能究竟有哪些呢&#xff1f;让AokSend来探个究竟。 腾…

map与set容器常见操作详解(含示例代码及注意事项)

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生 &#x1f648;个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&…

类与对象中C++

加油&#xff01;&#xff01;&#xff01; 文章目录 前言 一、类的6个默认成员函数 ​编辑 二、构造函数 1.概念 三、析构函数 1.概念 2.特性 四、拷贝构造函数 1.概念 2.特征 拷贝构造函数典型调用场景 五、赋值运算符重载 1.运算符重载 2.赋值运算符重载 赋值运算符重载格式…

【Qt】:坐标

坐标 一.常用快捷键二.使用帮助文档三.Qt坐标体系1.理论2.代码 一.常用快捷键 注释&#xff1a;ctrl / • 运⾏&#xff1a;ctrl R • 编译&#xff1a;ctrl B • 字体缩放&#xff1a;ctrl ⿏标滑轮 • 查找&#xff1a;ctrl F 比特就业课 • 整⾏移动&#xff1a;ctrl …

【Linux】体验一款开源的Linux服务器运维管理工具

今天为大家介绍一款开源的 Linux 服务器运维管理工具 - 1panel。 一、安装 根据官方那个提供的在线文档&#xff0c;这款工具的安装需要执行在线安装&#xff0c; # Redhat / CentOScurl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start…

.NET CORE使用Redis分布式锁续命(续期)问题

结合上一期 .NET CORE 分布式事务(三) DTM实现Saga及高并发下的解决方案(.NET CORE 分布式事务(三) DTM实现Saga及高并发下的解决方案-CSDN博客)。有的小伙伴私信说如果锁内锁定的程序或者资源未在上锁时间内执行完&#xff0c;造成的使用资源冲突&#xff0c;需要如何解决。本…

原创度检测工具分享,文章质量检测方便又简单

文章检测有利于我们了解文章内容的质量高低&#xff0c;而在以往我们检测文章只能依靠手动去检测&#xff0c;这是相当消耗工作时间的&#xff0c;但是在原创度检测工具出来之后&#xff0c;很多人开始检测文章质量就改用原创度检测工具了&#xff0c;因为使用原创度检测工具是…