/**
* 685. 冗余连接 II
* @author wsq
* @date 2020/09/17
在本问题中,有根树指满足以下条件的有向图。该树只有一个根节点,所有其他节点都是该根节点的后继。每一个节点只有一个父节点,除了根节点没有父节点。
输入一个有向图,该图由一个有着N个节点 (节点值不重复1, 2, ..., N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。
结果图是一个以边组成的二维数组。 每一个边 的元素是一对 [u, v],用以表示有向图中连接顶点 u 和顶点 v 的边,其中 u 是 v 的一个父节点。
返回一条能删除的边,使得剩下的图是有N个节点的有根树。若有多个答案,返回最后出现在给定二维数组的答案。
示例 1:
输入: [[1,2], [1,3], [2,3]]
输出: [2,3]
解释: 给定的有向图如下:
1
/ \
v v
2-->3
示例 2:
输入: [[1,2], [2,3], [3,4], [4,1], [1,5]]
输出: [4,1]
解释: 给定的有向图如下:
5 <- 1 -> 2
^ |
| v
4 <- 3
链接:https://leetcode-cn.com/problems/redundant-connection-ii
*/
package com.wsq.leetcode;
import java.util.Arrays;
public class FindRedundantDirectedConnection {
/**
* 题解参照:
* https://leetcode-cn.com/problems/redundant-connection-ii/solution/bing-cha-ji-java-by-liweiwei1419/
* @param edges
* @return
*/
public int[] findRedundantDirectedConnection(int[][] edges) {
// 边数统计
int len = edges.length;
// step1 入度统计
int[] inDegree = new int[len + 1];
for(int[] edge: edges) {
inDegree[edge[1]]++;
}
// step2: 删除入度为2的边,看看是否成形成环
// 由于题目要求删除靠后的边,因此这里删除的时候从后向前删除
for(int i = len - 1; i >= 0; i--) {
if(inDegree[edges[i][1]] == 2) {
if(!judgeCircle(edges, len, i)) {
return edges[i];
}
}
}
// step3:再尝试删除入度为1的边
for(int i = len -1; i >= 0; i--) {
if(inDegree[edges[i][1]] == 1) {
if(!judgeCircle(edges, len, i)) {
return edges[i];
}
}
}
throw new IllegalArgumentException("输入不符合要求。");
}
/**
* 检验除了 将要删除的边,其他边是否构成环
* @param edges
* @param len 节点总数
* @param removeEdgeIndex 删除的边的下标
* @return 构成环,返回true,否则返回False
*/
public boolean judgeCircle(int[][] edges, int len, int removeEdgeIndex) {
// 由于树节点是从1开始的,为了方便,使得创建父节点数组时多创建一个
UnionFind unionFind = new UnionFind(len + 1);
for(int i = 0; i < len; i++) {
if(i == removeEdgeIndex) {
continue;
}
if(!unionFind.union(edges[i][0], edges[i][1])) {
return true;
}
}
return false;
}
public class UnionFind{
// 存储父节点
private int[] parent;
public UnionFind(int n) {
parent = new int[n];
for(int i = 0; i < n; i++) {
parent[i] = i;
}
}
/**
* 寻找x的根节点,并且将所在路径进行压缩
* 最终目的就是将所有的节点都直接指向根节点
* @param x
* @return
*/
public int find(int x) {
while(x != parent[x]) {
// 路径压缩(隔代压缩)
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
/**
* 合并两节点
* @param x
* @param y
* @return 如果合并成功返回true
*/
public boolean union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if(rootX == rootY) {
return false;
}
parent[rootX] = rootY;
return true;
}
}
public static void main(String[] args) {
FindRedundantDirectedConnection f = new FindRedundantDirectedConnection();
int[][] edges = {{1, 2}, {2, 3}, {3, 1}, {1, 4}};
int[] res = f.findRedundantDirectedConnection(edges);
System.out.println(Arrays.toString(res));
}
}
685. 冗余连接 II
最新推荐文章于 2022-09-12 21:40:12 发布