【LeetCode每日一题】685. 冗余连接 II
685. 冗余连接 II
题目来源link
算法思想:树,深度优先遍历,有向图,并查集;
输入一个有向图,该图由一个有着N个节点 (节点值不重复1, 2, …, N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边
题目分析
分析来源link
定义:
冲突边:导致一个节点有两个父节点的边,如[[2,1],[3,1]],[3,1]则保存为冲突边。
成环边:导致产生环的边,如[[1,2],[2,3],[3,1]],[3,1]则保存为成环边。
所有情况分析:
1.无冲突,有环:无冲突,则直接返回成环边
例子:[[1,2], [2,3], [3,4], [4,1], [1,5]],此时[4,1]会产生环,但不产生冲突。
2.无环,有冲突:无环,则直接返回冲突边,即[u,v]
例子: [[1,2], [1,3], [2,3]],此时[2,3]会产生冲突,但不产生环。
3.有冲突,有环:这种情况下要保留冲突边,因为环的影响更优先于冲突,那么去掉环之中会导致冲突的那条边,即[parent[v],v]
例子:[[2,1],[3,1],[1,4],[4,2]],此时[3,1]产生冲突,[4,2]产生环,要保留冲突边[3,1],通过找到1的父节点,从而获得环之中的冲突边:[2,1]
数据结构–并查集
简述:一种快速获取两者是否存在于同一集合的数据结构,False则合并这两个集合,在这题中,True则表示成环。
java代码
代码来源link
class Solution {
public int[] findRedundantDirectedConnection(int[][] edges) {
//辅助数组parent以及并查集初始化
int nodesCount = edges.length;//边的数量=结点的数量
UnionFind uf = new UnionFind(nodesCount + 1);
int[] parent = new int[nodesCount + 1];//存放每个结点的父亲结点
for (int i = 1; i <= nodesCount; ++i) {
parent[i] = i;//初始化,每个结点的父亲结点是自己
}
//冲突/环标签
int conflict = -1;//冲突:该结点入度为2
int cycle = -1;//环:成环
//开始遍历
//[[1,2], [1,3], [2,3]]
for (int i = 0; i < nodesCount; ++i) {
int[] edge = edges[i];//获取其中一条边<node1,node2>;
int node1 = edge[0], node2 = edge[1];
if (parent[node2] != node2) {
conflict = i;
} else {
parent[node2] = node1;//改变父亲结点
if (uf.find(node1) == uf.find(node2)) {
//判断是否成环
cycle = i;
} else {
uf.union(node1, node2);//合并结点1和结点2
}
}
}
//获取有问题的边(冲突,环)
if (conflict < 0) {
//没有冲突,那意味着有成环;
int[] redundant = {
edges[cycle][0], edges[cycle][1]};
return redundant;
} else {
int[] conflictEdge = edges[conflict];//冲突边<node1,node2>;
if (cycle >= 0) {
int[] redundant = {
parent[conflictEdge[1]], conflictEdge[1]};
return redundant;
} else {
int[] redundant = {
conflictEdge[0], conflictEdge[1]};
return redundant;
}
}
}
}
//并查集:快速获取两者是否存在于同一集合;即判断是否有环
class UnionFind {
//用来存放边
int[] ancestor;
//初始化,每个结点指向的边是自己
public UnionFind(int n) {
ancestor = new int[n];
for (int i = 0; i < n; i++) {
ancestor[i] = i;
}
}
//将index1的集合加入到index2的集合中
public void union(int index1, int index2) {
ancestor[find(index1)] = find(index2);
}
//用来查找index的祖先
public int find(int index) {
if (ancestor[index] != index) {
ancestor[index] = find(ancestor[index]);
}
return ancestor[index];
}
}