版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mike_learns_to_rock/article/details/88597369
题目
找出有向图中,多余的连接;确保所有点都相连 && 每个节点只有一个parent(不包含root节点);如果有多个solution,去除靠后的连接;【题目保证去除一个连接,就可以满足要求】
Input: [[1,2], [1,3], [2,3]]
Output: [2,3]
Explanation: The given directed graph will be like this:
1
/ \
v v
2-->3
Input: [[1,2], [2,3], [3,4], [4,1], [1,5]]
Output: [4,1]
Explanation: The given directed graph will be like this:
5 <- 1 -> 2
^ |
| v
4 <- 3
分析
- 隐含条件:1)只有一个parent,如果一个节点有多个parent(这里是最多两个),肯定除去其中一个连接; 如果有两个parent,优先去除后面出现的连接;除非
1. 第二个连接里面包含了root && root只有一个儿子;
2. 第一个连接不可用,这里不可用的含义是:第一个连接的两个节点循环依赖
答案(后续优化)
class Solution {
class UnionFind {
private int union[];
private int rank[];
private int size = 0;
public UnionFind(int n) {
union = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++) {
union[i] = -1;
}
}
private int find(int i) {
while (i != union[i]) i = union[i];
return i;
}
public boolean union(int x, int y) {
if (union[x] == -1 || union[y] == -1) return false;
int rootx = find(x);
int rooty = find(y);
if (rootx == rooty) return true;
if (rank[rootx] > rank[rooty]) {
union[rooty] = rootx;
} else if (rank[rootx] < rank[rooty]) {
union[rootx] = rooty;
} else {
union[rooty] = rootx;
rank[rootx]++;
}
size--;
return false;
}
public void add(int i) {
if (union[i] == -1) {
union[i] = i;
size++;
}
}
public int getSize() {
return size;
}
}
public int[] findRedundantDirectedConnection(int[][] edges) {
// 记录每个节点的儿子们
Map<Integer, Set<Integer>> son = new HashMap<>();
// 记录每个节点的父亲们(正常只有一个)
Map<Integer, Set<Integer>> parent = new HashMap<>();
UnionFind uf = new UnionFind(edges.length);
int resIndex = -1;
int invalidSon = -1;
int firstParent = -1;
int secondParent = -1;
for (int i = 0; i < edges.length; i++) {
int x = edges[i][0];
int y = edges[i][1];
if (parent.get(y) == null) {
Set<Integer> set = new HashSet<>();
set.add(x);
parent.put(y, set);
} else {
Set<Integer> set = parent.get(y);
for (Integer e : set) {
firstParent = e.intValue();
}
set.add(x);
invalidSon = y;
secondParent = x;
}
if (son.get(x) == null) {
Set<Integer> set = new HashSet<>();
set.add(y);
son.put(x, set);
} else {
Set<Integer> set = son.get(x);
set.add(y);
}
}
// 这里很重要,判断两个parent的连接,应该去除谁
if (invalidSon > 0) {
int[] res = new int[2];
res[1] = invalidSon;
int firstGrandParent = 0;
Set<Integer> set = parent.get(firstParent);
if (set != null) {
for (Integer e : set) {
firstGrandParent = e.intValue();
}
}
if ((son.get(secondParent).size() == 1 && parent.get(secondParent) == null)
|| (firstGrandParent == invalidSon)) {
res[0] = firstParent;
} else{
res[0] = secondParent;
}
return res;
}
// 如果没有两个parent的情况,那么连通图中,找出多余连接
for (int i = 0; i < edges.length; i++) {
int x = edges[i][0];
int y = edges[i][1];
uf.add(x - 1);
uf.add(y - 1);
if (uf.union(x - 1, y - 1)) {
resIndex = i;
}
}
return edges[resIndex];
}
}