题目描述
在本问题中,有根树指满足以下条件的 有向 图。该树只有一个根节点,所有其他节点都是该根节点的后继。该树除了根节点之外的每一个节点都有且只有一个父节点,而根节点没有父节点。
输入一个有向图,该图由一个有着 n 个节点(节点值不重复,从 1 到 n)的树及一条附加的有向边构成。附加的边包含在 1 到 n 中的两个不同顶点间,这条附加的边不属于树中已存在的边。
结果图是一个以边组成的二维数组 edges 。 每个元素是一对 [ui, vi],用以表示 有向 图中连接顶点 ui 和顶点 vi 的边,其中 ui 是 vi 的一个父节点。
返回一条能删除的边,使得剩下的图是有 n 个节点的有根树。若有多个答案,返回最后出现在给定二维数组的答案。
示例 1:
输入: edges = [[1,2],[1,3],[2,3]]
输出: [2,3]
示例 2:
输入: edges = [[1,2],[2,3],[3,4],[4,1],[1,5]]
输出: [4,1]
解题思路
- 并查集模板代码
class UnionSet {
constructor (n) {
this.parent = new Array(n).fill(0).map((value, index) => index);
}
get (x) {
return this.parent[x] = (this.parent[x] == x ? x : this.get(this.parent[x]));
}
merge (a, b) {
this.parent[this.get(a)] = this.get(b);
}
}
代码
let findRedundantDirectedConnection = (edges) => {
let nodeNum = edges.length; // 获取边的长度,就是节点的个数
let uf = new UnionSet(nodeNum + 1); // 根据节点的个数构建并查集,加1避免它从0开始
let parent = []; // 怎么记录产生了两个父节点,整一个数组,记录每一个节点的父节点是多少
for(let i = 1;i <= (nodeNum + 1); i++){
parent[i] = i; // 做一个初始化
}
let conflict = -1; // 来记录是否产生了双重父节点的情况
let cycle = -1; // 来记录是否产生了环路
for(let i in edges) {
let edge = edges[i];
let node1 = edge[0], node2 = edge[1]; // 拿两个节点
if(parent[node2] != node2) { // node2这个节点有两个父节点
conflict = i; // 这是第几组数据,把他拿下来
} else { // 否者就是没有父节点,就把他们连起来
parent[node2] = node1;
if(uf.get(node1) == uf.get(node2)) { // 产生环路
cycle = i;
} else {
uf.merge(node1, node2); // 两种情况都没有,就给
}
}
}
if(conflict < 0) { // 没有双重父节点产生,就把环路给记录下来
// 只有环
return edges[cycle];
} else { // 有双重父节点产生
let conflictEdge = edges[conflict];
// 有两个入度的店,此时判断有无环
if(cycle >= 0) {
return [parent[conflictEdge[1]], conflictEdge[1]]
} else {
return conflictEdge;
}
}
};