在本问题中,有根树指满足以下条件的 有向 图。该树只有一个根节点,所有其他节点都是该根节点的后继。该树除了根节点之外的每一个节点都有且只有一个父节点,而根节点没有父节点。
输入一个有向图,该图由一个有着 n
个节点(节点值不重复,从 1
到 n
)的树及一条附加的有向边构成。附加的边包含在 1
到 n
中的两个不同顶点间,这条附加的边不属于树中已存在的边。
结果图是一个以边组成的二维数组 edges
。 每个元素是一对 [ui, vi]
,用以表示 有向 图中连接顶点 ui
和顶点 vi
的边,其中 ui
是 vi
的一个父节点。
返回一条能删除的边,使得剩下的图是有 n
个节点的有根树。若有多个答案,返回最后出现在给定二维数组的答案。
示例 1:

示例 2:

提示:
n == edges.length
3 <= n <= 1000
edges[i].length == 2
1 <= ui, vi <= n
该图由一个有着N个节点 (节点值不重复1, 2, …, N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。
这说明题目中的图原本是是一棵树,只不过在不增加节点的情况下多加了一条边
且该树只有一个根节点,即入度为0的节点只有一个
因为原本就是树,所以增加一条边有可能出现入度为2的顶点,也有可能没有入度为2的顶点(构成有向环)


思路:
情况1和情况2:
先获取入度为2的顶点,将其弧头加入list,有两个弧头(需要倒序遍历),因为答案要求删除后加入的边
如果list不为空,说明有入度为2的顶点
尝试删除其中一条边,删除后不构成有向环,就是要删除的边(删除后会出现有向环的只有情况1),如删除[3,2],图中存在环,那么必定是删除另一条边[1,2]
情况3:
已经确定图中有环,那么可以直接使用并查集
删除最后一条构成环的边即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| class Solution {
class UnionFind{ int[] father; public UnionFind(int n) { father = new int[n + 1]; for(int i = 1; i <= n; i++){ father[i] = i; } }
public int find(int u) { if(father[u] == u) return u; father[u] = find(father[u]); return father[u]; }
public boolean isSame(int u, int v) { return find(u) == find(v); }
public void join(int u, int v) { u = find(u); v = find(v); if(u != v) { father[v] = u; } } }
public boolean isTreeAfterRemoveEdge(int[][] edges, int deleteEdge){ UnionFind uf = new UnionFind(edges.length); for(int i = 0; i < edges.length; i++){ if(i == deleteEdge) continue; if(uf.isSame(edges[i][0], edges[i][1])){ return false; } uf.join(edges[i][0], edges[i][1]); } return true; }
int[] inDegree; public int[] findRedundantDirectedConnection(int[][] edges) { inDegree = new int[edges.length + 1]; for(int i = 0; i < edges.length; i++){ inDegree[edges[i][1]] ++; }
List<Integer> towDegree = new ArrayList<>(); for(int i = edges.length - 1; i >= 0; i --){ if(inDegree[edges[i][1]] == 2){ towDegree.add(i); } }
if(!towDegree.isEmpty()){ if(isTreeAfterRemoveEdge(edges, towDegree.get(0))){ return edges[towDegree.get(0)]; }else{ return edges[towDegree.get(1)]; } }
UnionFind uf = new UnionFind(edges.length); for(int i = 0; i < edges.length; i++){ if(uf.isSame(edges[i][0], edges[i][1])){ return edges[i]; } uf.join(edges[i][0], edges[i][1]);
} return null; } }
|