20240223-2092.查找所有有秘密的人

news2024/9/19 7:50:41

题目要求

给你一个整数 n,表示有 n 个人,编号从 0 到 n - 1。你还给你一个 0 索引的二维整数数组 meetings,其中 meetings[i] = [xi, yi, timei] 表示 xi 和 yi 在 timei 有一个会议。一个人可以同时参加多个会议。最后,给你一个整数 firstPerson。

人 0 有一个秘密,并在时间 0 开始与人 firstPerson 共享该秘密。更正式地说,在每次会面时,如果某人 xi 在时间 i 拥有该秘密,那么他将与某人 yi 共享该秘密,反之亦然。

秘密是即时共享的。也就是说,一个人收到秘密后,可以在同一时间内与其他会议上的人分享。

在所有会议结束后,返回所有拥有该秘密的人的名单。您可以按照任何顺序返回答案。

思路

我们需要找到所有会议结束之后(时间最后)拥有信息的人的名单,那么我们就需要将会议按照时间进行排序。

第二我们需要在同一会议时间判断出谁拥有秘密,谁在当前时间获得了秘密。然后这个过程继续传递直到时间结束。

在0时刻,编号为0和firstPerson的人获得了秘密。然后在之后的每一个时间点我们需要找到0和firstPerson和其他哪些人产生了交集,而后以此类推。

为了完成这一目的,根据建议我们应该采取并查集(Union-Find)的数据结构。

并查集是一种非常高效的数据结构,用于处理一些不交集的合并及查询问题,特别适用于本题中的场景,即追踪和管理一组动态集合的合并与查找操作。

并查集主要支持两种操作:

  • Find: 确定某个元素属于哪个集合,也就是这个元素的“根”是什么。在并查集中,每个集合由一个代表元素(根)来标识,所有属于同一集合的元素的根都是相同的。
  • Union: 将两个元素所在的集合合并为一个集合。这通常通过将一个集合的根元素连接到另一个集合的根元素来完成。

并查集通过数组或哈希表来实现,每个元素都有一个指向父元素的指针,根元素的指针指向它自己,这样形成一个树状结构。

基本操作的实现

  1. 初始化(Initialization):一开始,每个人都在自己独立的集合中,也就是每个人都是自己集合的根。

  2. 查找(Find):为了找到元素的根(代表元素),我们不断地追溯它的父元素,直到找到一个指向自己的元素,那就是根。在实际操作中,为了提高效率,我们会进行路径压缩,即在执行查找操作的同时,将查找路径上的所有元素直接连接到根上,这样可以减少后续查找操作的时间。

  3. 合并(Union):当我们想要合并两个元素所在的集合时,我们首先找到它们各自的根,如果根不同,就将其中一个根的父元素设置为另一个根,从而将两个树合并为一棵。为了保持树的平衡,通常会使用按秩合并,即总是将较小的树连接到较大的树上。

代码

#include <algorithm>
#include <unordered_set>
class UnionFind {
public:
    vector<int> parent;
    vector<int> rank;
    UnionFind(int size) : parent(size), rank(size, 0) {
        for (int i = 0; i < size; ++i) {
            parent[i] = i;
        }
    }

    int find(int x) {
        if (x != parent[x]) {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }

    void unionSet(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX != rootY) {
            if (rank[rootX] < rank[rootY]) {
                parent[rootX] = rootY;
            } else if (rank[rootX] > rank[rootY]) {
                parent[rootY] = rootX;
            } else {
                parent[rootY] = rootX;
                rank[rootX]++;
            }
        }
    }
};
class Solution {
public:

    vector<int> findAllPeople(int n, vector<vector<int>>& meetings, int firstPerson) {
        UnionFind uf(n);
        uf.unionSet(0, firstPerson);

        sort(meetings.begin(), meetings.end(), [](const vector<int>& a, const vector<int>& b) {
            return a[2] < b[2];
        });

        vector<int> secretHolders;
        for (int i = 0; i < meetings.size(); ) {
            int time = meetings[i][2];
            unordered_set<int> thisTimeMeeting;
            while (i < meetings.size() && meetings[i][2] == time) {
                uf.unionSet(meetings[i][0], meetings[i][1]);
                thisTimeMeeting.insert(meetings[i][0]);
                thisTimeMeeting.insert(meetings[i][1]);
                i++;
            }

            for (int person : thisTimeMeeting) {
                if (uf.find(person) != uf.find(0)) {
                    uf.parent[person] = person;
                }
            }
        }

        for (int i = 0; i < n; ++i) {
            if (uf.find(i) == uf.find(0)) {
                secretHolders.push_back(i);
            }
        }

        return secretHolders;
    }
};

时空复杂度

时间复杂度

空间复杂度

理解并查集

理解并查集的这种写法,我们可以分解为几个关键点:初始化、查找(Find)、合并(Union)以及路径压缩的实现。这些是并查集数据结构核心操作的实现,旨在高效处理动态连通性问题。

初始化(Constructor)

在并查集的构造函数中,每个元素最开始都指向自己,表示每个元素自成一个集合。rank数组用于记录每个根节点所在树的深度,有助于在执行合并操作时保持树的平衡,减少查找时间。

UnionFind(int size) : parent(size), rank(size, 0) {
    for(int i = 0; i < size; ++i) {
        parent[i] = i; // 每个节点的父节点指向自己
    }
}

查找(Find)

查找操作用于找到给定元素所在集合的根节点(代表元素)。路径压缩技术通过将查找路径上的每个节点直接链接到根节点,从而降低后续查找操作的复杂度。

int find(int x) {
    if(x != parent[x]) {
        parent[x] = find(parent[x]); // 路径压缩
    }
    return parent[x];
}

合并(Union)

合并操作用于将两个元素所在的集合合并为一个集合。它首先找到两个元素各自的根节点,如果根节点不同,说明它们属于不同的集合,需要合并。使用rank来决定如何合并,以保持树的平衡性,避免形成深度过大的树结构。

void unionSet(int x, int y) {
    int rootX = find(x);
    int rootY = find(y);
    if(rootX != rootY) {
        if(rank[rootX] < rank[rootY]) {
            parent[rootX] = rootY; // 将较浅的树的根节点指向较深的树的根节点
        } else if(rank[rootX] > rank[rootY]) {
            parent[rootY] = rootX;
        } else {
            parent[rootY] = rootX; // 如果深度相同,就选择一个作为根,增加其深度
            rank[rootX]++;
        }
    }
}

理解关键

  • 目的:并查集是为了高效地解决动态连通性问题设计的,它可以快速判断网络中任意两个点是否属于同一个连通分量,以及将两个连通分量合并。
  • 路径压缩:查找操作中的路径压缩是并查集高效的关键所在。通过将查找路径上的节点直接连接到根节点,可以显著降低后续查找的复杂度。
  • 按秩合并:通过比较两棵树的深度(秩)来决定合并方向,可以避免形成深度过大的树,从而保持操作的高效性。

通过这样的实现,我们可以非常高效地处理大量元素的动态联通性问题,这对于解决诸如网络连通性、集合合并等问题至关重要。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Flutter/Android】运行到安卓手机上一直卡在 Running Gradle task ‘assembleDebug‘... 的终极解决办法

方法步骤简要 查看你的Flutter项目需要什么版本的 Gradle 插件&#xff1a; 下载这个插件&#xff1a; 方法一&#xff1a;浏览器输入&#xff1a;https://services.gradle.org/distributions/gradle-7.6.3-all.zip 方法二&#xff1a;去Gradle官网找对应的版本&#xff1a;h…

个人机器人课程中最棘手的问题

爱好 22年&#xff0c;观点。当然现在自动驾驶研究路径已经不是22年的模式了。 23年&#xff0c;观点&#xff1a; 一个热爱自动驾驶但妥妥外行之人的思考-2023-CSDN博客 前篇 不合格机器人工程讲师为何不分享成功的案例-CSDN博客 在这篇文章中&#xff0c;有一段&#x…

Maya笔记 设置工作目录

Maya会把素材场景等自动保存在工作目录里&#xff0c;我们可以自己定义工作目录 步骤1 创建workspace.mel文件 文件/设置项目 ——>选择一个文件夹&#xff0c;点击设置——>创建默认工作区 这一个后&#xff0c;可以在文件夹里看到.mel文件 步骤2 自动创建文件夹…

进程的学习

进程基本概念: 1.进程: 程序&#xff1a;存放在外存中的一段数据组成的文件 进程&#xff1a;是一个程序动态执行的过程,包括进程的创建、进程的调度、进程的消亡 2.进程相关命令: 1.top 动态查看当前系统中的所有进程信息&#xff08;根据CPU占用率排序&#xf…

python中那些双下划线开头得函数和变量

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 Python中下划线—完全解读 Python 用下划线作为变量前缀和后缀指定特殊变量 _xxx 不能用from module import *导入 __xxx__ 系统定义名字 __xxx 类中的私有变量…

PC蓝牙通信

一、基本概念 蓝牙用于不同设备之间建立联系。利用无线电波在短距离间发送数据&#xff0c;wifi是在路由器跟设备间传输数据。蓝牙是在设备之间。蓝牙跟wifi同在2.4GHz频率下工作。蓝牙信号比wifi信号弱很多功率仅为1mW。传输距离有限。最初的1.0版本传输距离只有10m。现在5.0…

快速启动-后台管理系统

目录 Gitee人人开源 后端快速启动 1.clone仓库到本地 2.初始化数据库 3.更改数据库连接 4.启动项目验证 前端快速启动 1.克隆仓库 2.vsCode打开 3.控制台npm install 4.验证测试 时代已然不同&#xff0c;后台管理也可以使用脚手架方式快速启动。 Gitee人人开源 地…

JavaWeb——006MYSQL(DDLDML)

这里写目录标题 数据库开发-MySQL首先来了解一下什么是数据库。1. MySQL概述1.1 安装1.1.1 版本1.1.2 安装1.1.3 连接1.1.4 企业使用方式(了解) 1.2 数据模型1.3 SQL简介1.3.1 SQL通用语法1.3.2 分类 2. 数据库设计-DDL2.1 项目开发流程2.2 数据库操作2.2.1 查询数据库2.2.2 创…

Linux编程 1.2 系统文件IO- 使用

系统文件IO使用 1、open函数 #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> int open(const char* pathname,int flags); int open(const char* pathname,int flags,mode_t mode); 返回&#xff1a;若成功为文件描述符&#xff0c;若出错…

操作系统——处理机调度

文章目录 进程调度0.概念1.调度分类高级调度低级调度中级调度七状态模型调度对比 2.进程调度进程调度的时机进程调度的方式进程的切换方式调度器/调度程序闲逛进程 3. 调度算法的评价指标CPU利用率系统吞吐量周转时间等待时间响应时间 4. 调度算法先来先服务(FCFS)短作业优先(S…

微服务基础环境搭建

一.创建父工程 用于聚合其他微服务模块 1 新建 Maven 项目 JDK8Maven 项目Web 2 项目设置 编码的选择 UTF8JDK 版本的选择 3 删除 src 目录 4 配置父级 pom.xml SpringBoot&#xff1a;模块探究之spring-boot-dependencies-CSDN博客 子模块能够依赖当前父级 pom.xml 配置 【My…

LDR6020双盲插音频随便插充电听歌随便插

随着智能手机的普及和功能的日益丰富&#xff0c;手机已经成为我们日常生活中不可或缺的一部分。音乐、电影、游戏等娱乐内容更是丰富了手机的使用体验。而在这其中&#xff0c;音频转接器的作用愈发凸显&#xff0c;特别是在边听边充的场景下&#xff0c;一款高效且便捷的手机…

python脚本调用bitcoin-cli接口命令

脚本需求 1、python一个对外接口 2、不同的bitcoin命令通过传不同的参数实现 3、接口及接口的参数依次往后传递 4、日志全部打印到日志文件中并且日志文件按天进行切割 #!/usr/bin/python3from flask import Flask, request, jsonify import subprocess import json import os …

ROS中简单实现讯飞星火大模型API调用

文章目录 前言一、申请试用二、ROS中使用1.配置环境变量2.编写ros功能包总结前言 讯飞星火认知大模型是由科大讯飞自主研发的认知智能大模型,通过学习海量的文本、代码和图像,具备跨领域的知识和语言理解能力,能基于自然对话方式理解和执行任务。目前开放了API接口供用户使…

主数据管理是数字化转型成功的基石——江淮汽车案例分享

汽车行业数字化转型的背景 在新冠疫情导火索的影响下&#xff0c;经济全球化政治基础逐渐动摇。作为全球最大的汽车市场&#xff0c;我国的汽车市场逐渐由增量转为存量市场。 在数字化改革大背景下&#xff0c;随着工业4.0时代的到来&#xff0c;江淮汽车集团力争实现十四五数…

【汽车电子】万字详解汽车标定与XCP协议

XCP协议基础 文章目录 XCP协议基础一、引言1.1 什么是标定1.2 什么时候进行标定1.3 标定的意义 二、XCP协议简介2.1 xcp简介2.2 XCP如何加快开发过程&#xff1f;2.3 XCP的主要作用 三、XCP工作过程3.1 工作过程3.2 通讯模型3.3 测量与标定 四、XCP报文解析4.1 数据包报文格式4…

会分期完成2.3亿元C轮融资,它们都使用了拼音域名

易名科技()1月10日报道&#xff0c;致力于帮助租户缓解资金压力的汇分公司近日宣布完成2.3亿元C轮融资&#xff0c;由联络互动领投。 值得注意的是&#xff0c;它们都使用拼音域名。 他们分别是。 图&#xff1a;接触互动 汇分是汇房房旗下的租房分期平台。 打破了传统的押一付…

如何进行单元测试和集成测试

前端开发&#xff1a;如何进行单元测试和集成测试 在前端开发中&#xff0c;单元测试和集成测试是确保代码质量和稳定性不可或缺的一环。单元测试用于测试代码中的最小单元&#xff0c;而集成测试则是测试各个单元之间的交互和整体功能。通过合理的测试策略和工具&#xff0c;…

芯品荟 | 电动牙刷应用介绍

PART ONE 市场简介 - Market Profile - 电动牙刷个护是小家电最炙手可热的细分赛道之一。 随着居民的消费水平不断提升&#xff0c;口腔保健意识也逐步增强&#xff0c;中国电动牙刷市场迎来高速发展阶段。目前电动牙刷全球年用量在1亿只左右。 PART TWO 产品应用框图 - Bl…

【电机仿真】HFI算法脉振高频电压信号注入观测器-PMSM无感FOC控制

【电机仿真】HFI算法脉振高频电压信号注入观测器-PMSM无感FOC控制 文章目录 前言一、脉振高频电压注入法简介&#xff08;注入在旋转坐标系的d轴&#xff09;1.旋转高频电压&#xff08;电流&#xff09;注入法2.脉振高频电压注入法 二、高频注入理论1.永磁同步电机的高频模型2…