冗余连接
一、题目简介
在本问题中, 树指的是一个连通且无环的无向图。
输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, …, N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。
结果图是一个以边组成的二维数组。每一个边的元素是一对[u, v] ,满足 u < v,表示连接顶点u 和v的无向图的边。
返回一条可以删去的边,使得结果图是一个有着N个节点的树。如果有多个答案,则返回二维数组中最后出现的边。答案边 [u, v] 应满足相同的格式 u < v。
(题目来源:力扣(LeetCode))
示例 1:
输入: [[1,2], [1,3], [2,3]]
输出: [2,3]
解释: 给定的无向图为:
1
/ \
2 - 3
示例 2:
输入: [[1,2], [2,3], [3,4], [1,4], [1,5]]
输出: [1,4]
解释: 给定的无向图为:
5 - 1 - 2
| |
4 - 3
注意:
输入的二维数组大小在 3 到 1000。
二维数组中的整数在1到N之间,其中N是输入数组的大小。
二、解决方法
1. 并查集
package com.lxf.bcj;
public class FindRedundantConnection {
int[] parent;//父结点数组
public int[] findRedundantConnection(int[][] edges) {
int N=edges.length;//结点数
parent=new int[N+1];//空出0,让结点值直接对应数组下标
for (int i = 1; i <= N; i++) {
parent[i]=i;//父结点数组初始化
}
for (int[] edge : edges) {
if(find(edge[0])!=find(edge[1])){
//如果两个点的父节点不相同,直接合并
union(edge[0],edge[1]);
}else{
//如果两个点的父节点相同,说明当前两个结点相连后图成环
return edge;
}
}
return new int[0];
}
/**
* 查找当前结点的父结点方法
* @param index
* @return
*/
public int find(int index){
while(index!=parent[index]){
parent[index]=parent[parent[index]];
index=parent[index];
}
return index;
}
/**
* 合并集合
* @param index1
* @param index2
*/
public void union(int index1,int index2){
parent[find(index2)]=find(index1);
}
}
2.BFS(深度优先遍历算法)
题解区大佬方法:Java DFS/拓扑排序/并查集 实现
package com.lxf.bcj;
import java.util.HashSet;
import java.util.Set;
public class FindRedundantConnection {
public int[] findRedundantConnection(int[][] edges) {
// 树指的是一个连通且无环的无向图。
int len = edges.length;
//新建一个HashSet数组
Set<Integer>[] map = new HashSet[len + 1];
for(int[] edge: edges){
if(map[edge[0]] == null){
map[edge[0]] = new HashSet<>();
}
//第一个顶点下标对应的HashSet集合存储对应第二个顶点
map[edge[0]].add(edge[1]);
if(map[edge[1]] == null){
map[edge[1]] = new HashSet<>();
}
//第二个顶点下标对应的HashSet集合存储对应第一个顶点
map[edge[1]].add(edge[0]);
}
for(int i = len - 1; i >= 0; i--){
//移除当前两个顶点
map[edges[i][0]].remove(edges[i][1]);
map[edges[i][1]].remove(edges[i][0]);
//记录顶点是否已经遍历过
boolean[] used = new boolean[len + 1];
if(dfs(map, edges[i][1], edges[i][0], used)){
//如果这两个顶点还能连通,说明已经成环,返回这两个顶点
if(edges[i][1] < edges[i][0]){
return new int[]{edges[i][1], edges[i][0]};
}else{
return new int[]{edges[i][0], edges[i][1]};
}
}
}
return new int[0];
}
private boolean dfs(Set<Integer>[] map, int x, int y, boolean[] used){
//如果两个顶点相等,说明可以连通
if(x == y){
return true;
}
used[x] = true;//当前顶点已经遍历
for(int i: map[x]){
//遍历这个顶点对应的所有未遍历过的顶点
if(!used[i]){
if(dfs(map, i, y, used)){//递归操作
return true;
}
}
}
return false;
}
}