力扣链接
https://leetcode.cn/problems/maximum-employees-to-be-invited-to-a-meeting/
题目描述
示例
思路
本题题目倒是很好理解,也很容易知道要干嘛的,但是却不好写 写这道题前我们先了解一个东西——基环树
当基环只有两个节点的时候 很关键的是,基环节点是不是2个会有很大区别,我们看 当节点大于2个时候,这个环就不能插入其他人了,为啥呢,我们试试任意两个节点a,b之间插入一个c,我们知道,a,b之间是一条有向边,也就是要不就是a喜欢b,要不就是b喜欢a,这样才能开会,但如果你把c插进去,就会产生a不能和他喜欢的b坐一起(或者说b不能和他喜欢的a在一起),这样就不能达成题目要求了。所以说,当节点大于2个的时候,这个基环树上最大员工数量就是基环长度,我们记作max_ring_size
当节点等于两个的时候就不一样了,我们可以插到两边呀,比如这个图
0和1两边可以插入其他的节点,很明显,对于多个基环长度等于 2的基环树,每个基环树所对应的链,都可以拼在其余链的末尾,因此可以将这些链全部拼成一个圆桌,其大小记作 sumChainSize 由于给的输入数据可能含有多种基环树,所以最终的答案就是max(maxRingSize,sumChainSize)
python3代码
class Solution:
def maximumInvitations(self, favorite: List[int]) -> int:
n = len(favorite)
deg = [0] * n #这个deg用来统计第i个人被多少人喜欢
for f in favorite:
deg[f] += 1 # 统计基环树每个节点的入度
max_depth = [1] * n #这个用来统计树的深度
q = deque(i for i, d in enumerate(deg) if d == 0) #这个q队列存储的是那些树枝中最下层的节点,他们没有入度,下面这段代码主要就是为了减去所有树枝,只留基环
while q: # 拓扑排序,剪掉图上所有树枝
x = q.popleft() #先去掉一个一个节点
y = favorite[x] # 找到这个去除的节点喜欢谁
max_depth[y] = max_depth[x] + 1 #这个被喜欢的节点的深度当然等于x的深度+1
deg[y] -= 1 #因为x被减去了,把y的被喜欢-1
if deg[y] == 0: #如果没人喜欢y了,y就成了树枝中最下层的节点,给他加入q,然后马上就给他删了
q.append(y)
max_ring_size = sum_chain_size = 0 #这里前边介绍了
for i, d in enumerate(deg): #这里就是为了找到最大的基环长度
if d == 0: continue #没人喜欢,肯定不在环中,直接下一个
# 遍历基环上的点
deg[i] = 0 # 随便找一个有人喜欢的i,将基环上的点的入度标记为 0,避免重复访问
ring_size = 1 # 基环长度
x = favorite[i] #找到i喜欢谁
while x != i: #因为是一个环,就一直重复这个过程,知道最后转到自己,这样就知道环的长度了
deg[x] = 0 # 将基环上的点的入度标记为 0,避免重复访问
ring_size += 1
x = favorite[x]
if ring_size == 2: # 基环长度为 2
sum_chain_size += max_depth[i] + max_depth[favorite[i]] # 累加两条最长链的长度
else:
max_ring_size = max(max_ring_size, ring_size) # 取所有基环长度的最大值
return max(max_ring_size, sum_chain_size)
本文是参考leetcode题解中灵茶山艾府写成的,题目很难,题解也不好理解,所以我结合自己的理解写了这一篇文章,当然,最好还是自己debug一下看看过程,就很清楚
本文由博客一文多发平台 OpenWrite 发布!