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 原题链接和其他优选题解。

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

长距离工业RFID读写器的特点

长距离工业RFID读写器是一种特殊的RFID设备&#xff0c;能够在较远的距离内读取和写入RFID标签上的信息。这种读写器通常用于工业自动化、物流跟踪、车辆管理等领域&#xff0c;以实现高效、准确的跟踪和管理。 长距离工业RFID读写器采用先进的射频技术和信号处理技术&#xff…

needle库

python#导入需要的库import needle#定义代理主机和端口proxy_host"jshk.com.cn"proxy_port7894#使用needle库的网页爬虫功能&#xff0c;设置代理服务器参数&#xff0c;爬取https://read.jd.com/页面的HTML内容html_contentneedle.get("https://read.jd.com/&q…

SaaS 出海,如何搭建国际化服务体系?(三)

防噎指南&#xff1a;这可能是你看到的干货含量最高的 SaaS 出海经验分享&#xff0c;请准备好水杯&#xff0c;放肆食用&#xff08;XD。 当越来越多中国 SaaS 企业选择开启「国际化」副本&#xff0c;出海便俨然成为国内 SaaS 的新角斗场。 LigaAI 观察到&#xff0c;出海浪…

【SOC基础】单片机学习案例汇总 Part1:电机驱动、点亮LED

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

路由导航守卫

路由导航守卫有哪些&#xff1a; 全局守卫 组件内守卫 独享守卫 1.全局守卫 beforeEach 全局前置守卫 beforeResolve 全局解析守卫 afterEach 全局后置守卫 在创建实例的过程中&#xff0c;我们可以定义全局守卫&#xff1a; 2.独享守卫 beforeEnter 就是放到routes中定义的&…

上市公司-供应链效率数据集(2000-2022年)

参照张倩肖&#xff08;2023&#xff09;、Feng&#xff08;2015&#xff09;、张树山&#xff08;2023&#xff09;的做法&#xff0c;团队以库存周转天数来衡量供应链效率 库存周转天数有效克服了因企业保留安全库存而导致供应链效率较低的测算误差&#xff0c;体现供应链上…

MATLAB R2023a下载链接及软件安装教程

先解释下什么是A什么是B&#xff0c;省的有些小菜们总问。 a是上半年&#xff0c;b是下半年版本&#xff0c;但是有些小弱们总是觉得只要是b一定功能多&#xff0c;这不一定的&#xff0c;同年版本b比a可能稍微全点&#xff0c;不同年的&#xff0c;比如21b&#xff0c;22a&am…

最新ai系统ChatGPT商业运营版网站源码+支持GPT4.0/支持AI绘画+已支持OpenAI GPT全模型+国内AI全模型+绘画池系统

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

2103. 环和杆

2103. 环和杆 难度: 简单 来源: 每日一题 2023.11.02 总计有 n 个环&#xff0c;环的颜色可以是红、绿、蓝中的一种。这些环分别穿在 10 根编号为 0 到 9 的杆上。 给你一个长度为 2n 的字符串 rings &#xff0c;表示这 n 个环在杆上的分布。rings 中每两个字符形成一个…

新版Idea显示Git提交人信息

新版Idea的类和方法上会展示开发者信息 不想展示的话可以做以下配置&#xff1a;

ModStartCMS v7.5.0 内外网映射节流,安全使用增强

ModStart 是一个基于 Laravel 模块化极速开发框架。模块市场拥有丰富的功能应用&#xff0c;支持后台一键快速安装&#xff0c;让开发者能快的实现业务功能开发。 系统完全开源&#xff0c;基于 Apache 2.0 开源协议&#xff0c;免费且不限制商业使用。 功能特性 丰富的模块市…

找工作时如何快速了解一家公司?看他们招聘就知道

每一位求职者&#xff0c;都希望自己能够对感兴趣或者符合自己期望条件的公司有一个全面而深入的了解。如何在找工作或者找实习的时候&#xff0c;快速地了解一家公司&#xff0c;那就看看他们的招聘吧&#xff01; 1、从招聘信息洞察公司格局 有些公司的招聘信息中&#xf…

回归预测 | Matlab实现SO-CNN-SVM蛇群算法优化卷积神经网络-支持向量机的多输入单输出回归预测

Matlab实现SO-CNN-SVM蛇群算法优化卷积神经网络-支持向量机的多输入单输出回归预测 目录 Matlab实现SO-CNN-SVM蛇群算法优化卷积神经网络-支持向量机的多输入单输出回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.SO-CNN-SVM蛇群算法优化卷积神经网络-支持向量…

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…

移动硬盘只读模式怎么取消?

当硬盘驱动器处于为只读模式时&#xff0c;您仅能读取保存在该驱动器中的数据&#xff0c;但却无法添加新数据和修改当前数据。如果您想要对数据做一些改变就需要取消只读模式。那么&#xff0c;移动硬盘只读模式怎么取消&#xff1f; 方案一&#xff1a;使用命令提示符移除只读…

日本移动支付Merpay QA团队的自动化现状

Merpay是日本最大的网购平台之一Mercari的无现金支付系统。Merpay 的主要功能是让用户在 Mercari的网站上购物&#xff0c;也可以在日本的许多实体店和餐厅使用它&#xff0c;也可以理解为日本的“支付宝”。以下为Merpay QA 团队在自动化方面的一些思考&#xff1a; 这几年&am…

Linux0.11内核源码解析-malloc

malloc介绍 Linux内核版本0.11中的malloc.c文件实现了内存分配的功能。在这个版本的Linux内核中&#xff0c;malloc.c文件包含了内核级别的内存分配函数&#xff0c;用于分配和释放内核中的内存。这些函数可以帮助内核管理可用的内存&#xff0c;并允许内核动态地分配和释放内…

投资者如何保障个人利益?行业律师与欧科云链专家给出建议

香港作为全球加速拥抱Web3变革的引领之地&#xff0c;规定自今年6月起在香港经营虚拟资产服务业务需申领牌照。蜂拥而至的Web3创业公司&#xff0c;伺机而动的加密货币交易所&#xff0c;以及跃跃欲试的行业从业者&#xff0c;都让这座金融之都热闹非凡。但近期伴随JPEX诈骗案等…

基于单片机设计的电子柜锁

一、前言 随着现代社会的不断发展&#xff0c;电子柜锁的应用越来越广泛。传统的机械柜锁存在一些不便之处&#xff0c;例如钥匙容易丢失、密码容易泄露等问题。设计一款基于单片机的电子柜锁系统成为了一个有趣而有意义的项目。 该电子柜锁系统通过电磁锁作为柜锁的开关&…

【强化学习】14 —— A3C(Asynchronous Advantage Actor Critic)

A3C算法&#xff08; Asynchronous Methods for Deep Reinforcement Learning&#xff09;于2016年被谷歌DeepMind团队提出。A3C是一种非常有效的深度强化学习算法&#xff0c;在围棋、星际争霸等复杂任务上已经取得了很好的效果。接下来&#xff0c;我们先从A3C的名称入手&…