【每日一题Day365】LC2172参加会议的最多员工数 | 拓扑排序

简介: 【每日一题Day365】LC2172参加会议的最多员工数 | 拓扑排序

参加会议的最多员工数【LC2127】

一个公司准备组织一场会议,邀请名单上有 n 位员工。公司准备了一张 圆形 的桌子,可以坐下 任意数目 的员工。

员工编号为 0 到 n - 1 。每位员工都有一位 喜欢 的员工,每位员工 当且仅当 他被安排在喜欢员工的旁边,他才会参加会议。每位员工喜欢的员工 不会 是他自己。

给你一个下标从 0 开始的整数数组 favorite ,其中 favorite[i] 表示第 i 位员工喜欢的员工。请你返回参加会议的 最多员工数目 。

思路:拓扑排序

  • 内向基环树概念:从i向favorite[i]连边,可以得到一张有向图。由于每个大小为k的连通块都有k个点和k边,所以每个连通块必定有且仅有一个环,且由于每个点的出度均为 1,这样的有向图又叫做内向基环树
  • 本题中有两种基环树

长度为2时,圆桌上可以放置多个长度等于2的环,及其最长链

长度大于2时,圆桌上只能放置一个长度大于2的环

因为相邻员工都需要有一位喜欢的员工

长度等于2的环内两位员工互相喜欢,在其边上可以再增加最长链【贪心,获得最多员工】,最长链的末尾又可以添加其他长度为2的环【结果1】

长度大于2的环内无法再添加其他员工【结果2】

最终答案为结果1和结果2的最大值

实现

可以使用拓扑排序找到基环和数值,并记录每个节点的最长链,计算两种内向基环树对应的结果

通过一次拓扑排序,可以「剪掉」所有树枝。因为拓扑排序后,树枝节点的入度均为 0,基环节点的入度均为 1。这样就可以将基环和树枝区分开,从而简化后续处理流程:

如果要遍历基环,可以从入度为 1的节点出发,遍历其余入度为 1 的节点。

如果要遍历树枝,可以以基环与树枝的连接处为起点,顺着反图来遍历树枝,从而将问题转化成一个树形问题。

作者:灵茶山艾府

链接:https://leetcode.cn/problems/maximum-employees-to-be-invited-to-a-meeting/

来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution {
    public int maximumInvitations(int[] favorite) {
        int n = favorite.length;
        int[] deg = new int[n];
        for (int f : favorite) {
            deg[f]++; // 统计基环树每个节点的入度
        }
        int[] maxDepth = new int[n];
        Deque<Integer> q = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            if (deg[i] == 0) {
                q.add(i);
            }
        }
        while (!q.isEmpty()) { // 拓扑排序,剪掉图上所有树枝
            int x = q.poll();
            int y = favorite[x]; // x 只有一条出边
            maxDepth[y] = maxDepth[x] + 1;
            if (--deg[y] == 0) {
                q.add(y);
            }
        }
        int maxRingSize = 0, sumChainSize = 0;
        for (int i = 0; i < n; i++) {
            if (deg[i] == 0) continue;
            // 遍历基环上的点
            deg[i] = 0; // 将基环上的点的入度标记为 0,避免重复访问
            int ringSize = 1; // 基环长度
            for (int x = favorite[i]; x != i; x = favorite[x]) {
                deg[x] = 0; // 将基环上的点的入度标记为 0,避免重复访问
                ringSize++;
            }
            if (ringSize == 2) { // 基环长度为 2
                sumChainSize += maxDepth[i] + maxDepth[favorite[i]] + 2; // 累加两条最长链的长度
            } else {
                maxRingSize = Math.max(maxRingSize, ringSize); // 取所有基环长度的最大值
            }
        }
        return Math.max(maxRingSize, sumChainSize);
    }
}
作者:灵茶山艾府
链接:https://leetcode.cn/problems/maximum-employees-to-be-invited-to-a-meeting/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度

时间复杂度:O ( n )

空间复杂度:O ( n )

目录
相关文章
|
Shell Linux API
【Shell 命令集合 磁盘维护 】Linux 查找指定目录下的所有符号链接文件 symlinks 命令使用教程
【Shell 命令集合 磁盘维护 】Linux 查找指定目录下的所有符号链接文件 symlinks 命令使用教程
230 1
|
测试技术 数据安全/隐私保护
软件测试制度-新手小白如何制定测试管理工作规范?
软件测试制度-新手小白如何制定测试管理工作规范?
458 1
|
人工智能 数据挖掘
这图怎么画| 气泡热图(基因表达泛癌分析)
这图怎么画| 气泡热图(基因表达泛癌分析)
351 0
elementUI el-upload上传组件实战使用
elementUI el-upload上传组件实战使用
|
前端开发 JavaScript 搜索推荐
打造个人博客网站:从零开始的HTML和CSS之旅
【9月更文挑战第32天】在这个数字化的时代,拥有一个个人博客不仅是展示自我的平台,也是技术交流的桥梁。本文将引导初学者理解并实现一个简单的个人博客网站的搭建,涵盖HTML的基础结构、CSS样式的美化技巧以及如何将两者结合来制作一个完整的网页。通过这篇文章,你将学会如何从零开始构建自己的网络空间,并在互联网世界留下你的足迹。
|
数据处理 数据格式
|
10月前
|
存储 SQL 前端开发
【若依RuoYi-Vue | 项目实战】帝可得后台管理系统(二)
接着上回的【若依RuoYi-Vue | 项目实战】基于若依的帝可得后台管理系统(一),本次我们继续完成人员管理、设备管理、策略管理模块的开发。
1650 6
【若依RuoYi-Vue | 项目实战】帝可得后台管理系统(二)
|
移动开发 安全 API
微信H5支付--微信JS-SDK支付--点金计划
本文详细介绍了微信H5支付和JS-SDK支付的原理、配置和开发流程,涵盖了H5支付在移动端浏览器外唤起微信支付的细节,以及JS-SDK支付在微信内置浏览器中完成支付的相关注意事项。文章还针对微信支付常见问题,提供了解决方案和代码示例。最后,文章深入解析了微信支付点金计划,包括商家小票的自定义开发、API接口以及支付成功后的页面展示逻辑,为开发者提供了完整的开发参考。
795 0
微信H5支付--微信JS-SDK支付--点金计划
|
JSON Java 网络架构
elasticsearch学习四:使用springboot整合 rest 进行搭建elasticsearch服务
这篇文章介绍了如何使用Spring Boot整合REST方式来搭建和操作Elasticsearch服务。
341 4
elasticsearch学习四:使用springboot整合 rest 进行搭建elasticsearch服务
|
数据采集 存储 人工智能
《文档智能 & RAG让AI大模型更懂业务解决方案评测》
本文介绍了通过文档智能和RAG技术将业务文档整合到大语言模型(LLM)知识库中的实践原理,涵盖了理解情况、技术细节、部署体验、知识库优势及适用场景。重点讨论了文档解析、信息提取、语义理解等步骤,以及RAG技术在LLM中的应用。同时,提出了在技术细节、部署引导、知识库更新和性能优化等方面的改进建议,强调了该方案在企业内部知识管理、客户服务和业务流程自动化中的适用性,但也指出了在安全性、系统集成和性能稳定性方面的不足。
252 0