In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) for which all other nodes are descendants of this node, plus every node has exactly one parent, except for the root node which has no parents.
The given input is a directed graph that started as a rooted tree with n nodes (with distinct values from 1 to n), with one additional directed edge added. The added edge has two different vertices chosen from 1 to n, and was not an edge that already existed.
The resulting graph is given as a 2D-array of edges. Each element of edges is a pair [ u i , v i ] [u_i, v_i] [ui,vi] that represents a directed edge connecting nodes u i u_i ui and v i v_i vi, where u i u_i ui is a parent of child v i v_i vi.
Return an edge that can be removed so that the resulting graph is a rooted tree of n nodes. If there are multiple answers, return the answer that occurs last in the given 2D-array.
Input: edges = [[1,2],[1,3],[2,3]]
Output: [2,3]
Input: edges = [[1,2],[2,3],[3,4],[4,1],[1,5]]
Output: [4,1]
From: LeetCode
Link: 685. Redundant Connection II
1. Detect if any node has two parents.
2. If found, store both edges.
3. Use Union-Find to detect cycles.
4. Based on what we find:
int find(int* parent, int x) {
if (parent[x] != x)
parent[x] = find(parent, parent[x]);
return parent[x];
}
bool unionSet(int* parent, int* rank, int u, int v) {
int pu = find(parent, u);
int pv = find(parent, v);
if (pu == pv) return false; // cycle
if (rank[pu] > rank[pv]) parent[pv] = pu;
else if (rank[pu] < rank[pv]) parent[pu] = pv;
else {
parent[pu] = pv;
rank[pv]++;
}
return true;
}
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* findRedundantDirectedConnection(int** edges, int edgesSize, int* edgesColSize, int* returnSize) {
int* parent = (int*)malloc((edgesSize + 1) * sizeof(int));
int* rank = (int*)calloc(edgesSize + 1, sizeof(int));
int* candidate1 = NULL;
int* candidate2 = NULL;
int* parents = (int*)calloc(edgesSize + 1, sizeof(int));
for (int i = 1; i <= edgesSize; ++i)
parents[i] = i;
// Step 1: Check for a node with two parents
for (int i = 0; i < edgesSize; ++i) {
int u = edges[i][0], v = edges[i][1];
if (parents[v] != v) {
candidate1 = (int*)malloc(2 * sizeof(int));
candidate2 = (int*)malloc(2 * sizeof(int));
candidate1[0] = parents[v];
candidate1[1] = v;
candidate2[0] = u;
candidate2[1] = v;
edges[i][0] = -1; // Mark this edge to skip in union-find
} else {
parents[v] = u;
}
}
// Step 2: Union-Find to detect cycle
for (int i = 1; i <= edgesSize; ++i)
parent[i] = i;
for (int i = 0; i < edgesSize; ++i) {
int u = edges[i][0], v = edges[i][1];
if (u == -1) continue; // skip the second parent edge
if (!unionSet(parent, rank, u, v)) {
free(parent); free(rank); free(parents);
*returnSize = 2;
if (candidate1)
return candidate1;
int* result = (int*)malloc(2 * sizeof(int));
result[0] = u; result[1] = v;
return result;
}
}
// If no cycle was detected, the second edge is the redundant one
free(parent); free(rank); free(parents);
*returnSize = 2;
return candidate2;
}