剑指Offer题目笔记33(并查集)

面试题116:

面试题116

解决方案:

​ 一个班级可以包含一个或多个朋友圈,对应的图中可能包含一个或多个子图,每个朋友圈对应一个子图。因此,这个问题可以转化为如何求图中子图的数目。图的搜索算法可以用来计算图中子图的数目。扫描图中所有的节点。如果某个节点v之前没有访问过,就搜索它所在的子图。当所有节点都访问完之后,就可以知道图中有多少个子图。

源代码(使用图的搜索):
class Solution {
    public int findCircleNum(int[][] isConnected) {
        boolean[] visited = new boolean[isConnected.length];
        int result = 0;
        for(int i = 0;i < isConnected.length;i++){
            if(!visited[i]){
                findCircle(isConnected,visited,i);
                result++;
            }  
        }

        return result;
    }

	//遍历同学i的朋友
    private void findCircle(int[][] isConnected,boolean[] visited,int i){
        Queue<Integer> queue = new LinkedList<>();
        queue.add(i);
        visited[i] = true;
        while(!queue.isEmpty()){
            int t = queue.remove();
            for(int friend = 0;friend < isConnected.length;friend++){
                if(isConnected[t][friend] == 1 && !visited[friend]){
                    queue.add(friend);
                    visited[friend] = true;
                }
            }
        }
    }
}
源代码(并查集):
class Solution {
    public int findCircleNum(int[][] isConnected) {
        int[] fathers = new int[isConnected.length];
        for(int i = 0;i < fathers.length;i++){
            fathers[i] = i;
        }

        int count = fathers.length;
        for(int i = 0;i < isConnected.length;i++){
            for(int j = i+1;j < isConnected.length;j++){
                if(isConnected[i][j] == 1 && union(fathers,i,j)){
                    count--;
                }
            }
        }

        return count;
    }
    
	//如果它们的根节点不相同,那么合并他们的朋友圈,如果相同,那么直接返回false
    private boolean union(int[] fathers,int i,int j){
        int fatherOfI = findFather(fathers,i);
        int fatherOfJ = findFather(fathers,j);
        if(fatherOfI != fatherOfJ){
            fathers[fatherOfI] = fatherOfJ;
            return true;
        }

        return false;
    }
    
	//压缩路径,使fathers[i]保存的是子集的根节点
    private int findFather(int[] fathers,int i){
        if(fathers[i] != i){
            fathers[i] = findFather(fathers,fathers[i]);
        }

        return fathers[i];
    }
}

面试题117:

面试题117

解决方案:

​ 把输入数组中的每个字符串看成图中的一个节点。如果两个字符串相似,那么它们对应的节点之间有一条边相连,也就属于同一个子图。例如,字符串[“tars”,“rats”,“arts”,“star”]根据相似性分别属于两个子图。

源代码:
class Solution {
    public int numSimilarGroups(String[] strs) {
        int[] fathers = new int[strs.length];
        for(int i = 0;i < fathers.length;i++){
            fathers[i] = i;
        }

        int groups = strs.length;
        for(int i = 0;i < strs.length;i++){
            for(int j = i + 1;j < strs.length;j++){
                if(similar(strs[i],strs[j]) && union(fathers,i,j)){
                    groups--;
                }
            }
        }

        return groups;
    }

    private boolean similar(String str1,String str2){
        int diffCount = 0;
        for(int i = 0;i < str1.length();i++){
            if(str1.charAt(i) != str2.charAt(i)){
                diffCount++;
            }
        }

        return diffCount <= 2;
    }

    //如果它们的根节点不相同,那么合并子集,如果相同,那么直接返回false
    private boolean union(int[] fathers,int i,int j){
        int fatherOfI = findFather(fathers,i);
        int fatherOfJ = findFather(fathers,j);
        if(fatherOfI != fatherOfJ){
            fathers[fatherOfI] = fatherOfJ;
            return true;
        }

        return false;
    }
    
    //压缩路径,使fathers[i]保存的是子集的根节点
    private int findFather(int[] fathers,int i){
        if(fathers[i] != i){
            fathers[i] = findFather(fathers,fathers[i]);
        }

        return fathers[i];
    }
}

面试题118:

面试题118

解决方案:
  1. 逐步在图中添加5条边以便找出形成环的条件。最开始的时候图中的5个节点是离散的,任意两个节点都没有边相连。也就是说,图被分割成5个子图,每个子图只有一个节点。
  2. 通过一步步在图中添加边可以发现判断一条边会不会导致环的规律。如果两个节点分别属于两个不同的子图,添加一条边连接这两个节点,会将它们所在的子图连在一起,但不会形成环。如果两个节点属于同一个子图,添加一条边连接这两个节点就会形成一个环。
源代码:
class Solution {
    public int[] findRedundantConnection(int[][] edges) {
        int maxVertex = 0;
        //找出节点个数
        for(int[] edge:edges){
            maxVertex = Math.max(maxVertex,edge[0]);
            maxVertex = Math.max(maxVertex,edge[1]);
        }
        
        int[] fathers = new int[maxVertex+1];
        //将n个节点初始化为n个子集,每个节点的根节点都指向它自己
        for(int i = 1;i <= maxVertex;i++){
            fathers[i] = i;
        }

        for(int[] edge:edges){
            if(!union(fathers,edge[0],edge[1])){
                return edge;
            }
        }

        return new int[2];
    }
    
	//合并子集
    private boolean union(int[] fathers,int i,int j){
        int fatherOfI = findFather(fathers,i);
        int fatherOfJ = findFather(fathers,j);
        if(fatherOfI != fatherOfJ){
            fathers[fatherOfI] = fatherOfJ;
            return true;
        }

        return false;
    }

    //压缩路径,使fathers[i]保存的是子集的根节点
    private int findFather(int[] fathers,int i){
        if(fathers[i] != i){
            fathers[i] = findFather(fathers,fathers[i]);
        }

        return fathers[i];
    }
}

面试题119:

面试题119

解决方案:

​ 这个题目是关于整数的连续性的。如果将每个整数看成图中的一个节点,相邻的(数值大小相差1)两个整数有一条边相连,那么这些整数将形成若干子图,每个连续数值序列对应一个子图。计算最长连续序列的长度就转变成求最大子图的大小。

源代码(使用广度优先搜索):
class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for(int num:nums){
            set.add(num);
        }

        int longest = 0;
        while(!set.isEmpty()){
            Iterator<Integer> iter = set.iterator();
            longest = Math.max(longest,bfs(set,iter.next()));
        }

        return longest;
    }
    
	//搜索最长数字连续的最长序列
    private int bfs(Set<Integer> set,int num){
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(num);
        set.remove(num);
        int length = 1;
        while(!queue.isEmpty()){
            int i = queue.poll();
            int[] neighbors = new int[]{i-1,i+1};
            for(int neighbor:neighbors){
                if(set.contains(neighbor)){
                    queue.offer(neighbor);
                    set.remove(neighbor);
                    length++;
                }
            }
        }

        return length;
    }
}
源代码(使用并查集):
class Solution {
    public int longestConsecutive(int[] nums) {
        Map<Integer,Integer> fathers = new HashMap<>();
        //保存每个数字的最长数字序列
        Map<Integer,Integer> counts = new HashMap<>();
        Set<Integer> all = new HashSet<>();
        for(int num:nums){
            fathers.put(num,num);
            counts.put(num,1);
            all.add(num);
        }

        for(int num:nums){
            //如果数组中存在num + 1的数字,那就两个子集合并
            if(all.contains(num + 1)){
                union(fathers,counts,num,num+1);
            }
			//如果数组中存在num - 1的数字,那就两个子集合并
            if(all.contains(num-1)){
                union(fathers,counts,num,num-1);
            }
        }

        int longest = 0;
        for(int length:counts.values()){
            longest = Math.max(longest,length);
        }

        return longest;
    }

    private int findFather(Map<Integer,Integer> fathers,int i){
        if(fathers.get(i) != i){
            fathers.put(i,findFather(fathers,fathers.get(i)));
        }

        return fathers.get(i);
    }

    private void union(Map<Integer,Integer> fathers,Map<Integer,Integer> counts,int i,int j){
        int fatherOfI = findFather(fathers,i);
        int fatherOfJ = findFather(fathers,j);
        if(fatherOfI != fatherOfJ){
            fathers.put(fatherOfI,fatherOfJ);
            int countOfI = counts.get(fatherOfI);
            int countOfJ = counts.get(fatherOfJ);
            //合并后,长度也叠加
            counts.put(fatherOfJ,countOfI + countOfJ);
        }
    }
}

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

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

相关文章

企业Linux特殊权限位/为什么会存在SUID?/企业环境测试(原理剖析)-4989字解析

企业高薪思维&#xff1a; 坚持很难&#xff0c;优秀的人才是少数&#xff0c;很重要 坚持不下去&#xff0c;问自己想要什么&#xff1f; 问问自己想要好的生活状态&#xff1f;问自己有背景吗&#xff1f;你学历是亮点吗&#xff1f;有钱没&#xff0c;你也就是一般家庭&…

selenium 下载文件取消安全下载的方法

问题描述 我要从一个网站上下载文件&#xff0c;谷歌浏览器总是自动阻止下载&#xff0c;并询问我是否保留。 可是&#xff0c;我想要的是不要询问&#xff0c;默认下载即可。 运行环境 OS: macOSselenium: 4.19.0python: 3.10.11Chrome: 124.0.6367.62selenium chromedrive…

工会排队模式:创新营销的双赢之道

工会排队模式全面解读 在当今数字化营销的大潮中&#xff0c;促销方式层出不穷&#xff0c;但能真正抓住消费者眼球并带来双方共赢的模式并不多见。而工会排队模式便是在这样的背景下崭露头角&#xff0c;它巧妙地融合了工会积分、奖金池与排队机制&#xff0c;为消费者与商家…

linux进阶篇:重定向和管道操作

Linux中的重定向和管道操作 llinux中的三种IO设备&#xff1a; 标准输入&#xff08;STDIN&#xff09;,文件描述符号为&#xff1a;0&#xff0c;默认从键盘获取输入 标准输出&#xff08;STDOUT&#xff09;,文件描述符号位&#xff1a;1&#xff0c;默认输出到显示终端 标准…

java宠物领养系统的设计与实现(springboot+mysql+源码)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的宠物领养系统的设计与实现。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 基于Spring Bo…

udemy视频教程下载:AI和ChatGPT提示工程精通指南

欢迎来到 ChatGPT 大师班&#xff01; 这个 ChatGPT 大师班&#xff1a;AI 和提示工程指南是您通往 AI 未来的全通道通行证。 以下是您的学习旅程&#xff1a; 理解和掌握 ChatGPT&#xff1a;您将深入了解 AI 和语言模型&#xff0c;重点是 ChatGPT。我们设计了这个部分&am…

Linux--进程间的通信-命名管道

前文&#xff1a; Linux–进程间的通信-匿名管道 Linux–进程间的通信–进程池 命名管道的概念 命名管道是一种进程间通信&#xff08;IPC&#xff09;机制&#xff0c;运行不同进程之间进行可靠的、单向或双向的数据通信。 特点和作用&#xff1a; 跨平台性&#xff1a;在W…

ue4打包多模块

首先&#xff0c;每个模块&#xff0c;包含插件内的模块在内&#xff0c;都要用IMPLEMENT_MODULE(类名, 模块名)的方式&#xff0c;模块名就是带.build.cs的第一个单词。 build.cs里就说了这个模块该怎么用&#xff0c;用c#编写。 打包中要考虑到target.cs,将工程中相应的模块…

Linux服务器磁盘满了如何清理

生产环境中&#xff0c;磁盘很容易被日志文件沾满&#xff0c;如何查找和清理呢&#xff1f; 分享一下个人的经验&#xff1a; 1.先查询到哪个磁盘占用的最多 使用命令&#xff1a;df -h 2.查询/目录下磁盘占用情况 使用命令&#xff1a;du -sh * 3.同理进入占用磁盘比较大…

聊聊binlog是什么

1. 上一讲思考題解答:redo日志刷盘策略的选择建议 先给大家解释一下上一讲的思考題&#xff0c;我给大家的一个建议&#xff0c;其实对于redo日志的三种刷盘策略&#xff0c;我们通常建议是设置为1 也就是说&#xff0c;提交事务的时候&#xff0c;redo日志必须是刷入磁盘文件…

接口测试之用Fiddler对手机app进行抓包

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

基于FPGA的OMEGA东京奥运会计时器

截至2019年共举办了31届奥运会&#xff0c;其中27届的计时设备都由欧米茄&#xff08;OMEGA&#xff0c;Ω&#xff09;提供&#xff0c;今年的东京奥运会将会是第28届。 瑞士计时公司&#xff08;Swiss Timing&#xff09;基于火星Mars ZX2核心板打造了为奥运会等大型体育赛事…

Redis教程——数据类型(哈希、集合)

上篇文章我们学习了Redis教程——数据类型&#xff08;字符串、列表&#xff09;&#xff0c;这篇文章学习Redis教程——数据类型&#xff08;哈希表、集合&#xff09; 哈希表Hash 哈希表是一个string类型的field(字段)和value(值)的映射表&#xff0c;hash特别适合用于存储…

web轮播图

思路&#xff1a; 例如&#xff1a;有5张轮播的图片&#xff0c;每张图片的宽度为1024px、高度为512px.那么轮播的窗口大小就应该为一张图片的尺寸&#xff0c;即为&#xff1a;1024512。之后将这5张图片0px水平相接组成一张宽度为&#xff1a;5120px,高度依然为&#xff1a;5…

问题解决:pip install __命令安装不了Python库

项目环境&#xff1a; 我的环境&#xff1a;Window10&#xff0c;Python3.7&#xff0c;Anaconda3-2.4.0&#xff0c;Pycharm2023.1.3 问题描述①&#xff1a; pip install 命令安装不了需要的安装的Python库&#xff0c;以PyMuPDF为例 1 socket.timeout: The read operation t…

ICASSP 2024会议现场第四弹 晚会上韩风歌舞惊喜连连

会议之眼 快讯 在科技的浪潮中&#xff0c;ICASSP 2024会议作为全球信号处理领域的风向标&#xff0c;今日在充满活力韩国迎来了它的第五天日程&#xff01;会场中热烈的讨论和灵感迸发的交流&#xff0c;让会场仿佛成为一座思想的熔炉&#xff0c;不断燃烧着创新的火花&#…

2024经常用且免费的10个网盘对比,看看哪个比较好用!

网盘在我们的工作和学习中经常会用到&#xff0c;也是存储资料的必备工具&#xff0c;有了它&#xff0c;我们就不用走到哪都带着移动硬盘了&#xff0c;而目前市场上的主流网盘还有数十款&#xff0c;其中有免费的也有付费的&#xff0c;各家不一&#xff0c;今天小编就来为您…

ins视频批量下载,instagram批量爬取视频信息【爬虫实战课1】

简介 Instagram 是目前最热门的社交媒体平台之一,拥有大量优质的视频内容。但是要逐一下载这些视频往往非常耗时。在这篇文章中,我们将介绍如何使用 Python 编写一个脚本,来实现 Instagram 视频的批量下载和信息爬取。 我们使用selenium获取目标用户的 HTML 源代码,并将其保存…

Unity解决:导出安卓apk 安装时报错:应用未安装:软件包似乎无效

Unity2018.4.36 导出安卓apk 安装时报错&#xff1a;应用未安装&#xff1a;软件包似乎无效 解决办法&#xff1a;因为安装到安卓12 需要添加添加过滤规则 在AS工程AndroidManifest.xml 添加过滤规则即可。 android:exported"true"

爬虫 | 网易新闻热点数据的获取与保存

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本项目是一个简单的网络爬虫&#xff0c;用于从网易新闻的热点新闻列表中提取标题和对应的链接&#xff0c;并将提取到的数据保存到一个 CSV 文件中。 目录 一、技术栈 二、功能说明 三、注意事项 四、代码解析 1. 导入所需…