你正在维护一个项目,该项目有 n
个方法,编号从 0
到 n - 1
。
给你两个整数 n
和 k
,以及一个二维整数数组 invocations
,其中 invocations[i] = [ai, bi]
表示方法 ai
调用了方法 bi
。
已知如果方法 k
存在一个已知的 bug。那么方法 k
以及它直接或间接调用的任何方法都被视为 可疑方法 ,我们需要从项目中移除这些方法。
只有当一组方法没有被这组之外的任何方法调用时,这组方法才能被移除。
返回一个数组,包含移除所有 可疑方法 后剩下的所有方法。你可以以任意顺序返回答案。如果无法移除 所有 可疑方法,则 不 移除任何方法。
示例 1:
输入: n = 4, k = 1, invocations = [[1,2],[0,1],[3,2]]
输出: [0,1,2,3]
解释:
方法 2 和方法 1 是可疑方法,但它们分别直接被方法 3 和方法 0 调用。由于方法 3 和方法 0 不是可疑方法,我们无法移除任何方法,故返回所有方法。
示例 2:
输入: n = 5, k = 0, invocations = [[1,2],[0,2],[0,1],[3,4]]
输出: [3,4]
解释:
方法 0、方法 1 和方法 2 是可疑方法,且没有被任何其他方法直接调用。我们可以移除它们。
示例 3:
输入: n = 3, k = 2, invocations = [[1,2],[0,1],[2,0]]
输出: []
解释:
所有方法都是可疑方法。我们可以移除它们。
一个项目有 n 个方法,其中第 k 个方法有 bug。可能是第 k 个方法自己的 bug,也可能是第 k 个方法调用的更底层的方法有 bug。
你需要删除所有可能有 bug 的方法。如果删除后无法编译(剩余的方法调用了删除的方法),那么返回数组 [0,1,2,⋯,n−1]。
如果可以正常删除,返回剩余的方法编号。
思路
从 k 开始 DFS 图,标记所有可能有 bug 的方法(节点)。题目把这些方法叫做可疑方法。
遍历 invocations,如果存在从「非可疑方法」到「可疑方法」的边,则删除后无法编译,返回数组 [0,1,2,⋯,n−1]。
否则可以正常删除,把非可疑方法加入答案。
⚠注意:图中可能有环,为避免 DFS 无限递归下去,只需 DFS 没有访问过(没有被标记)的节点。
class Solution:
def remainingMethods(self, n: int, k: int, invocations: List[List[int]]) -> List[int]:
g = [[] for _ in range(n)]
for x, y in invocations:
g[x].append(y)
# 收集所有可疑方法
suspicious = set()
def dfs(x: int) -> None:
suspicious.add(x)
for y in g[x]:
if y not in suspicious: # 避免无限递归
dfs(y)
dfs(k)
# 检查是否有【非可疑方法】->【可疑方法】的边
for x, y in invocations:
if x not in suspicious and y in suspicious:
# 无法移除可疑方法
return list(range(n))
# 移除所有可疑方法
return list(set(range(n)) - suspicious)
参考: