fromtypingimportListclassSolution:deffindRedundantDirectedConnection(self,edges:List[List[int]])->List[int]:n=len(edges)# Step 1: Find a node with two parents (in-degree 2)parent=[0]*(n+1)candidate1=None# earlier edge u1 -> vcandidate2=None# later edge u2 -> vforu,vinedges:ifparent[v]==0:parent[v]=uelse:candidate1=[parent[v],v]candidate2=[u,v]break# Step 2: Union-Find to detect a cycleuf=list(range(n+1))deffind(x:int)->int:whileuf[x]!=x:uf[x]=uf[uf[x]]# path halvingx=uf[x]returnxforu,vinedges:# Temporarily ignore candidate2ifcandidate2isnotNoneand[u,v]==candidate2:continueru,rv=find(u),find(v)ifru==rv:# Cycle detectedifcandidate1isnotNone:# Removing candidate2 still leaves a cycle,# so candidate1 must be removedreturncandidate1# No node with two parents: this edge forms the cyclereturn[u,v]uf[ru]=rv# No cycle after removing candidate2 -> candidate2 is redundantreturncandidate2Approach
There are only two possible kinds of invalid edges in this problem:
- A node has two parents — one of its two incoming edges must be removed.
- There is a cycle — the edge that closes the cycle must be removed.
The algorithm:
· First, scan edges to find a node v with two parents. Store the earlier edge as candidate1 and the later edge as candidate2.
· Run Union-Find while skipping candidate2:
· If a cycle still appears, then candidate1 is the redundant edge.
· If no cycle appears, then candidate2 is the redundant edge.
· If no node has two parents, simply return the first edge that creates a cycle.
Complexity
· Time: O(n · α(n)), effectively O(n) with union-find.
· Space: O(n) for the union-find and parent arrays.