当前位置: 首页 > news >正文

2127. 参加会议的最多员工数 : 啥是内向/外向基环树(拓扑排序)

题目描述

这是 LeetCode 上的 「2127. 参加会议的最多员工数」 ,难度为 「困难」

Tag : 「拓扑排序」、「内向基环树」、「图」

一个公司准备组织一场会议,邀请名单上有 n 位员工。

公司准备了一张圆形的桌子,可以坐下任意数目的员工。

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

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

示例 1: alt

输入:favorite = [2,2,1,2]

输出:3

解释:
上图展示了公司邀请员工 0,1 和 2 参加会议以及他们在圆桌上的座位。
没办法邀请所有员工参与会议,因为员工 2 没办法同时坐在 0,1 和 3 员工的旁边。
注意,公司也可以邀请员工 1,2 和 3 参加会议。
所以最多参加会议的员工数目为 3 。

示例 2:

输入:favorite = [1,2,0]

输出:3

解释:
每个员工都至少是另一个员工喜欢的员工。所以公司邀请他们所有人参加会议的前提是所有人都参加了会议。
座位安排同图 1 所示:
- 员工 0 坐在员工 2 和 1 之间。
- 员工 1 坐在员工 0 和 2 之间。
- 员工 2 坐在员工 1 和 0 之间。
参与会议的最多员工数目为 3 。

示例 3: alt

输入:favorite = [3,0,1,4,1]

输出:4

解释:
上图展示了公司可以邀请员工 0,1,3 和 4 参加会议以及他们在圆桌上的座位。
员工 2 无法参加,因为他喜欢的员工 0 旁边的座位已经被占领了。
所以公司只能不邀请员工 2 。
参加会议的最多员工数目为 4 。

提示:

内向基环树 + 拓扑排序

根据题意,圆形桌上 左右两边只要有一位是 所喜欢即可。

我们可从 添加有向边,从而得到一张包含多个「内向基环树」的图。

内向基环树,是指其满足基环树定义,且内向 bushi

基环树是指其具有 个点 条边的联通块,而「内向」是指树中任意节点有且只有一条出边,对应的「外向」是指树中任意节点有且只有一条入边。

例如,左图内向,右图外向:

alt

根据题意,「圆桌最多放置一个长度大于 的环(内向环,只有一条出边,即只有一个喜欢的人,安插其他非环成员,会破坏留下参加会议的必要条件),但可放置多个长度为 的环,且多个环可延伸出最长链(利用左右两侧只需有一个喜欢的人即满足)。」

在「取长度大于 的最大环」及「多个长度为 的环及其最长链之和」两者中取最大长度即是答案。

alt
alt

Java 代码:

class Solution {
    public int maximumInvitations(int[] favorite) {
        int n = favorite.length;
        // in 统计每个节点的入度情况, max 统计节最长链
        int[] in = new int[n], max = new int[n];
        for (int x : favorite) in[x]++;
        Deque<Integer> d = new ArrayDeque<>();
        for (int i = 0; i < n; i++) {
            if (in[i] == 0) d.addLast(i);
        }
        // 拓扑排序: 求基环外的最长链
        while (!d.isEmpty()) {
            int cur = d.pollFirst(), ne = favorite[cur];
            max[ne] = Math.max(max[ne], max[cur] + 1);
            if (--in[ne] == 0) d.addLast(ne);
        }
        // 圆桌最多放置一个大于 2 的环(ans1 统计最大值)
        // 圆桌可放置多个等于 2 的环(ans2 累加该长度)
        int ans1 = 0, ans2 = 0;
        for (int i = 0; i < n; i++) {
            if (in[i] == 0continue;
            int j = favorite[i], cur = 1;
            while (j != i) {
                // 一个环只需被处理一次, 这里将环中其他节点入度置 0, 下次遍历到这些点就会被跳过
                in[j] = 0;
                j = favorite[j];
                cur++;
            }
            if (cur == 2) ans2 += 2 + max[i] + max[favorite[i]];
            else ans1 = Math.max(ans1, cur);
        }
        return Math.max(ans1, ans2);
    }
}

Python 代码:

class Solution:
    def maximumInvitations(self, favorite: List[int]) -> int:
        n = len(favorite)
        # in_degree 统计每个节点的入度情况, max_length 统计节最长链
        in_degree, max_length = [0] * n, [0] * n
        for x in favorite:
            in_degree[x] += 1
        d = deque()
        for i in range(n):
            if in_degree[i] == 0:
                d.append(i)
       # 拓扑排序: 求基环外的最长链
        while d:
            cur = d.popleft()
            ne = favorite[cur]
            max_length[ne] = max(max_length[ne], max_length[cur] + 1)
            in_degree[ne] -= 1
            if in_degree[ne] == 0:
                d.append(ne)
        # 圆桌最多放置一个大于 2 的环(ans1 统计最大值)
        # 圆桌可放置多个等于 2 的环(ans2 累加该长度)
        ans1, ans2 = 00
        for i in range(n):
            if in_degree[i] == 0:
                continue
            j, cur = favorite[i], 1
            while j != i:
                # 一个环只需被处理一次, 这里将环中其他节点入度置 0, 下次遍历到这些点就会被跳过
                in_degree[j] = 0
                j = favorite[j]
                cur += 1
            if cur == 2:
                ans2 += 2 + max_length[i] + max_length[favorite[i]]
            else:
                ans1 = max(ans1, cur)
        return max(ans1, ans2)

C++ 代码:

class Solution {
public:
    int maximumInvitations(vector<int>& favorite) {
        int n = favorite.size();
        // in 统计每个节点的入度情况, max_length 统计节最长链
        vector<intin(n, 0);
        vector<intmax_length(n, 0);
        for (int x : favorite) in[x]++;
        deque<int> d;
        for (int i = 0; i < n; i++) {
            if (in[i] == 0) d.push_back(i);
        }
        // 拓扑排序: 求基环外的最长链
        while (!d.empty()) {
            int cur = d.front();
            d.pop_front();
            int ne = favorite[cur];
            max_length[ne] = max(max_length[ne], max_length[cur] + 1);
            if (--in[ne] == 0) d.push_back(ne);
        }
        // 圆桌最多放置一个大于 2 的环(ans1 统计最大值)
        // 圆桌可放置多个等于 2 的环(ans2 累加该长度)
        int ans1 = 0, ans2 = 0;
        for (int i = 0; i < n; i++) {
            if (in[i] == 0continue;
            int j = favorite[i], cur = 1;
            while (j != i) {
                // 一个环只需被处理一次, 这里将环中其他节点入度置 0, 下次遍历到这些点就会被跳过
                in[j] = 0;
                j = favorite[j];
                cur++;
            }
            if (cur == 2) ans2 += 2 + max_length[i] + max_length[favorite[i]];    
            else ans1 = max(ans1, cur);
        }
        return max(ans1, ans2);
    }
};

TypeScript 代码:

function maximumInvitations(favorite: number[]): number {
    const n = favorite.length;
    // in_degree 统计每个节点的入度情况, max_length 统计节最长链
    const in_degree = Array(n).fill(0), max_length = Array(n).fill(0);
    for (const x of favorite) in_degree[x]++;
    const d = [];
    for (let i = 0; i < n; i++) {
        if (in_degree[i] === 0) d.push(i);
    }
    // 拓扑排序: 求基环外的最长链
    while (d.length > 0) {
        const cur = d.shift() as number;
        const ne = favorite[cur];
        max_length[ne] = Math.max(max_length[ne], max_length[cur] + 1);
        if (--in_degree[ne] === 0) d.push(ne);
    }
    // 圆桌最多放置一个大于 2 的环(ans1 统计最大值)
    // 圆桌可放置多个等于 2 的环(ans2 累加该长度)
    let ans1 = 0, ans2 = 0;
    for (let i = 0; i < n; i++) {
        if (in_degree[i] === 0continue;
        let j = favorite[i], cur = 1;
        while (j !== i) {
            // 一个环只需被处理一次, 这里将环中其他节点入度置 0, 下次遍历到这些点就会被跳过
            in_degree[j] = 0;
            j = favorite[j];
            cur++;
        }
        if (cur == 2) ans2 += 2 + max_length[i] + max_length[favorite[i]];    
        else ans1 = Math.max(ans1, cur);
    }
    return Math.max(ans1, ans2);
};
  • 时间复杂度:统计入度的复杂度为 ;拓扑排序求最长链复杂度为 ;计算答案过程中,每个点最多被访问两次(环内节点),复杂度为 。整体复杂度为
  • 空间复杂度:

最后

这是我们「刷穿 LeetCode」系列文章的第 No.2217 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。

为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。

在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉

相关文章:

2127. 参加会议的最多员工数 : 啥是内向/外向基环树(拓扑排序)

题目描述 这是 LeetCode 上的 「2127. 参加会议的最多员工数」 &#xff0c;难度为 「困难」。 Tag : 「拓扑排序」、「内向基环树」、「图」 一个公司准备组织一场会议&#xff0c;邀请名单上有 n 位员工。 公司准备了一张圆形的桌子&#xff0c;可以坐下任意数目的员工。 员工…...

Qt入门日记1

目录 1.Qt简介和案例 2.第一个Qt程序 3.学会查看帮助文档 4.创建一个按钮 5.对象树简介 6.Qt的坐标系 7. 信号和槽 7.1自定义信号和槽 7.2信号连接信号 7.3拓展 7.4Qt4版本以前的connect 1.Qt简介和案例 Qt是一个跨平台的C图形用户界面应用程序框架(就是一个库吧…...

SpringBoot_第七章(读写分离)

这里列举了三种读写分离实现方案,分别是如下三种 1&#xff1a;MybatisPlus&#xff08;读写分离&#xff09; 1.1&#xff1a;首先创建三个数据库1主2从 表名是user表 1.2&#xff1a;代码实例 1&#xff1a;导入pom <!--MybatisPlus的jar 3.0基于jdk8--><depend…...

linux下mysql-8.2.0集群部署(python版本要在2.7以上)

目录 一、三台主机准备工作 1、mysql官方下载地址&#xff1a;https://dev.mysql.com/downloads/ 2、修改/etc/hosts 3、关闭防火墙 二、三台主机安装mysql-8.2.0 1、解压 2、下载相应配置 3、初始化mysql&#xff0c;启动myslq&#xff0c;设置开机自启 4、查看初始密…...

40 深度学习(四):卷积神经网络|深度可分离卷积|colab和kaggle的基础使用

文章目录 卷积神经网络为什么要卷积卷积的具体流程池化tensorflow代码 深度可分离卷积原理介绍计算量对比代码参数计算例子 colab 和 kagglecolabkaggle如何在colab上使用kaggle的数据 卷积神经网络 卷积神经网络的基本结构 1&#xff1a; (卷积层(可选)池化层) * N全连接层 *…...

Spring Boot面向切面加注解

一.项目pom.xml文件引入切面依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId> </dependency>二.定义注解类 import java.lang.annotation.*;/*** desc 错误日志注解* au…...

uniapp小程序授权统一处理

1.使用 1.将工具代码引入到utils中 const authorize (scope, isOne false, isMust false) > {if (!scope || !authorizeObj[scope]) {return console.error(请传输需要获取权限的 scope&#xff0c;详见,https://uniapp.dcloud.net.cn/api/other/authorize.html#scope-…...

光学仿真|优化汽车内部照明体验

当我们谈论优化人类感知的内部照明时&#xff0c;我们实际上指的是两个重点领域&#xff1a;安全性和驾驶员体验。如果内部照明可以提供尽可能最佳的体验&#xff0c;驾驶员则能够更好地应对颇具挑战性或意外的驾驶状况&#xff0c;并且减轻疲劳感。除了功能优势外&#xff0c;…...

Spring XML使用CASE WHEN处理SELECT字段

在日常开发中&#xff0c;经常会碰到需要导出的情况。而一些枚举值或者状态一般是定义成整型&#xff0c;这个时候需要对数据进行转换&#xff0c;转换成对应的文本再导出。 在XML中用CASE WHEN来根据不同的查询结果做不同的处理。 比如 SELECT name AS 姓名, age AS 年龄 C…...

关于C#中使用多线程的讨论

关于C#中使用多线程的讨论 C# 中 Thread 调用的函数有返回值 没有输入应该如何解决 如果你想在一个新的线程中调用一个带返回值但没有输入参数的函数,可以使用 Thread 类的委托 ThreadStart 来创建一个新的线程,并在其中调用该函数。然后,你可以使用 Thread 类的 Join 方法…...

工程机械数字孪生可视化平台建设,推动大型装备智能化数字化转型升级

随着信息技术的迅猛发展&#xff0c;数字孪生技术作为一项新兴技术应运而生。数字孪生是指通过数学模型和仿真技术&#xff0c;将实际物理对象与其数字化虚拟模型相互关联&#xff0c;实现对物理对象的全生命周期管理和智能优化。在工程机械领域&#xff0c;巨蟹数科从数字孪生…...

Linux 网络流量监控利器 iftop命令详解及实战

简介 iftop 是什么 在 Linux 系统下即时监控服务器的网络带宽使用情况&#xff0c;有很多工具&#xff0c;比如 iptraf、nethogs 等等&#xff0c;但是推荐使用小巧但功能很强大的 iftop 工具。 iftop 是 Linux 系统一个免费的网卡实时流量监控工具&#xff0c;类似于 top 命令…...

protected by SourceGuardian and requires a SourceGuardian loader ‘ixed.8解决方案

php相关问题 安装程序提示以下内容 遇到某些php程序的安装提示&#xff1a; PHP script ‘/www/wwwroot/zhengban.youyacao.com/install/index.php’ is protected by SourceGuardian and requires a SourceGuardian loader ‘ixed.8.1.lin’ to be installed. 1) Click her…...

KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(14)

接前一篇文章:KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(13) 上一回讲完了drivers/gpu/drm/drm_framebuffer.c中的framebuffer_check函数中的第一个for循环,本回继续讲解framebuffer_check()接下来的代码。为了便于理解,再次贴出其源码,如下所示: static …...

2023-macOS下安装anaconda,终端自动会出现(base)字样,如何取消

2023-macOS下安装anaconda&#xff0c;终端自动会出现(base)字样&#xff0c;如何取消 安装后&#xff0c;我们再打开终端&#xff0c;就会自动出现了&#xff08;base&#xff09; 就会出现这样子的&#xff0c;让人头大&#xff0c; 所以我们要解决它 具体原因是 安装了anac…...

Nginx搭载负载均衡及前端项目部署

目录 ​编辑 一.Nginx安装 1.安装所需依赖 2.下载并解压Nginx安装包 3.安装nginx 4.启动Nginx服务 二.Tomcat负载均衡 1.准备环境 1.1 准备两个Tomcat 1.2 修改端口号 1.3 配置Nginx服务器集群 2.效果展示 ​编辑三.前端项目打包 ​编辑四.前端项目部署 1.上传项目…...

深度学习——炼丹

学习率调整策略 自定义学习率调整策略 简单版 net MyNet()optimoptim.Adam(net.parameters(),lr0.05) for param_group in optim.param_groups: param_group["lr"] param_group["lr"]*0.5print(param_group["lr"]) #0.25复杂版&#…...

Matlab中的app设计

1.窗口焦点问题&#xff1a; 窗口焦点问题&#xff1a;确保你的应用程序窗口正常处于焦点状态。有时&#xff0c;其他窗口的弹出或焦点切换可能导致应用程序最小化。点击应用程序窗口以确保它处于焦点状态。 窗口管理&#xff1a;确保你的 MATLAB 或操作系统没有未处理的错误或…...

曾经遇到过的无法解释的问题

因为不能直接展示生产数据与生产数据结构&#xff0c;所以写一个简单的例子 class Stu{ private String name; private int age; getter setter constructor 略 } List<Stu> list new ArrayList(); list.add(new Stu("s1",16)); list.add(new Stu("…...

基于uniapp与uview做一个按拼音首字母排序的通讯录页面

效果图&#xff1a; 第一步导入pinyin库并应用&#xff0c;用于区分汉字的拼音首字母 npm i pinyin import pinyin from "pinyin" 完整算法&#xff1a; function getListByPinyinFirstLetter(data) {const newList {};for (const item of data) {let firstLett…...

网络工程师-入门基础课:华为HCIA认证课程介绍

【微/信/公/众/号&#xff1a;厦门微思网络】 华为HCIA试听课程&#xff1a;超级实用&#xff0c;华为VRP系统文件详解 华为HCIA试听课程&#xff1a;不会传输层协议&#xff0c;HCIA都考不过 华为HCIA试听课程&#xff1a;网络工程师的基本功&#xff1a;网络地址转换NAT 一…...

玻色量子成功研制光量子计算专用光纤恒温控制设备——“量晷”

​近日&#xff0c;北京玻色量子科技有限公司&#xff08;以下简称“玻色量子”&#xff09;成功研制出一款高精度量子计算专用光纤恒温控制设备——“量晷”&#xff0c;该设备能将光纤的温度变化稳定在千分之一摄氏度量级&#xff0c;即能够做到0.001C的温度稳定维持&#xf…...

力扣:147. 对链表进行插入排序(Python3)

题目&#xff1a; 给定单个链表的头 head &#xff0c;使用 插入排序 对链表进行排序&#xff0c;并返回 排序后链表的头 。 插入排序 算法的步骤: 插入排序是迭代的&#xff0c;每次只移动一个元素&#xff0c;直到所有元素可以形成一个有序的输出列表。每次迭代中&#xff0c…...

OpenCV4(C++)——形态学(腐蚀、膨胀)

文章目录 一、腐蚀&#xff08;erode&#xff09;二、膨胀&#xff08;dilate&#xff09;三、形态学操作四、总结 一、腐蚀&#xff08;erode&#xff09; OpenCV 4提供了用于图像腐蚀的erode()函数。 void cv::erode(src, dst, kernel, anchor, iterations, borderType, bo…...

C++设计模式_24_Visitor 访问器

Visitor 访问器也是属于“行为变化”模式。 文章目录 1. 动机( Motivation)2. 代码演示Visitor 访问器3. 模式定义4. 结构(Structure)5. 要点总结6. 其他参考1. 动机( Motivation) 在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基…...

el-tabel表格加个多选框

<template><div><el-checkbox v-model"checked" :disabled"checkedDis" change"onAllSelectChange">多选框</el-checkbox>点击多选框&#xff0c;禁用列表复选框<el-table ref"multipleTable" :data"…...

Go语言集成开发环境(IDE):GoLand 2023中文

GoLand 2023是一款由JetBrains开发的现代化、功能丰富的Go语言集成开发环境&#xff08;IDE&#xff09;。它提供了智能代码提示和自动完成、强大的内置调试器以及代码重构工具&#xff0c;帮助开发者提高编码效率并确保代码质量。GoLand 2023还支持多种版本控制系统&#xff0…...

opencv c++ canny 实现 以及与halcon canny的对比

Opencv和C实现canny边缘检测_opencv边缘增强-CSDN博客 一、canny实现步骤 1、图像必须是单通道的&#xff0c;也就是说必须是灰度图像 2、图像进行高斯滤波&#xff0c;去掉噪点 3、sobel 算子过程的实现&#xff0c;计算x y方向 、梯度&#xff08;用不到&#xff0c;但是…...

阿里云无影升级2.0 云电脑解决方案时代到来

10月31日&#xff0c;杭州云栖大会上&#xff0c;阿里云宣布无影全新升级2.0&#xff1a;从云电脑到云上解决方案&#xff0c;帮助中小企业更便捷地构建云上办公&#xff0c;并开放无影产品及解决方案能力&#xff0c;为生态合作伙伴提供企业云平台&#xff0c;帮助其打造定制化…...

【案例展示】多物理场仿真软件介绍

本期案例来自上海交通大学微波与射频研究中心团队&#xff0c;团队针对集成电路技术发展过程中面临的挑战&#xff0c;通过FastCAE平台对自研多物理场仿真求解器进行功能拓展与集成&#xff0c;使用户可基于不同的电、热、应力场景和仿真需求&#xff0c;灵活设定参数进行快速准…...