【教3妹学编辑-算法题】参加会议的最多员工数

64 阅读3分钟

阳光明媚

2哥 :“我要飞的更高, 飞的更高哦……” 3妹:2哥唱的啥呀, 都跑调啦 2哥 :3妹,昨天神州十六返回舱成功着陆,载人飞行任务取得圆满成功。中国真是太厉害了。 3妹:是啊, 此生无悔入华夏~不跟你多说了, 我要去公司开会了。 2哥:开会,这么早啊! 3妹:是啊,没办法,打工人,打工人。 2哥:正好我看到一个会议的算法,你看看能做出来吗?

题目

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

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

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

示例 1: image.png

输入: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: image.png 输入:favorite = [3,0,1,4,1] 输出:4 解释: 上图展示了公司可以邀请员工 0,1,3 和 4 参加会议以及他们在圆桌上的座位。 员工 2 无法参加,因为他喜欢的员工 0 旁边的座位已经被占领了。 所以公司只能不邀请员工 2 。 参加会议的最多员工数目为 4 。

提示:

n == favorite.length 2 <= n <= 10^5 0 <= favorite[i] <= n - 1 favorite[i] != i

思路:

思考

分类讨论 + 拓扑排序

java代码:

class Solution {
    public int maximumInvitations(int[] favorite) {
        int n = favorite.length;
        // 统计入度,便于进行拓扑排序
        int[] indeg = new int[n];
        for (int i = 0; i < n; ++i) {
            ++indeg[favorite[i]];
        }
        boolean[] used = new boolean[n];
        int[] f = new int[n];
        Arrays.fill(f, 1);
        Queue<Integer> queue = new ArrayDeque<Integer>();
        for (int i = 0; i < n; ++i) {
            if (indeg[i] == 0) {
                queue.offer(i);
            }
        }
        while (!queue.isEmpty()) {
            int u = queue.poll();
            used[u] = true;
            int v = favorite[u];
            // 状态转移
            f[v] = Math.max(f[v], f[u] + 1);
            --indeg[v];
            if (indeg[v] == 0) {
                queue.offer(v);
            }
        }
        // ring 表示最大的环的大小
        // total 表示所有环大小为 2 的「基环内向树」上的最长的「双向游走」路径之和
        int ring = 0, total = 0;
        for (int i = 0; i < n; ++i) {
            if (!used[i]) {
                int j = favorite[i];
                // favorite[favorite[i]] = i 说明环的大小为 2
                if (favorite[j] == i) {
                    total += f[i] + f[j];
                    used[i] = used[j] = true;
                }
                // 否则环的大小至少为 3,我们需要找出环
                else {
                    int u = i, cnt = 0;
                    while (true) {
                        ++cnt;
                        u = favorite[u];
                        used[u] = true;
                        if (u == i) {
                            break;
                        }
                    }
                    ring = Math.max(ring, cnt);
                }
            }
        }
        return Math.max(ring, total);
    }
}