java并查集判断是否是连通图_连通图(并查集)

题目截图:

348a34bc5cf3e68e4c66bfb1dd833cdc.png

题目大意:给定一个二维数组代表一个有向图(数组中每个一维数组[A,B]代表由A指向B的边),图中共有N个结点(标号为1-N)和N条有向边,我们需要删除一条边,使这个有向图变成一个具有根节点的连通树,找出这条边并返回(如果有多种可能,返回靠后的边)。

解题报告:

题目中给出的有向图有三种情况:

1. 某一个结点有两个父节点,图中无环。

2. 除根结点外每个结点都只有一个父节点,图中有环。

3. 某一个结点有两个父节点,图中有环。

对于以上三种情况,有如下两种考虑:

1. 如果存在某一个结点有两个父节点,记录下指向这个结点的两条边,那么需要删除的边必然在这两条边中选择。我们首先将靠后的那条边除去,看看剩下的有向图中是否存在环,如果不存在环,则说明我们的选择是对的,直接返回靠后的边,如果仍然存在环,说明之前的选择是错误的,需要返回靠前的边。

2. 如果不存在某一个结点有两个父节点,那么说明有向图中必然出现了环。我们只需要找到哪条边使得有向图出现了环,并且返回。

题目理解到这里,思路就很清晰,难点在于如何判断有向图是否出现了环?这里引入并查集的概念,如果不了解,可以查看另外一篇博客http://blog.csdn.net/u013546077/article/details/64509038,然后再回来看代码。

代码:

class Solution {

public int[] findRedundantDirectedConnection(int[][] edges) {

int[] can1={-1,-1};

int[] can2={-1,-1};

int len=edges.length;

int[] root=new int[len+1];

for(int i=0;i

int[] edge=edges[i];

if(root[edge[1]]==0){

root[edge[1]]=edge[0];

}else{

can2=new int[]{edge[0],edge[1]};

can1=new int[]{root[edge[1]],edge[1]};

edge[1]=0;

}

}

for(int i=0;i<=len;i++){

root[i]=i;

}

for(int[] edge:edges){

if(edge[1]==0){

continue;

}

if(find(root,edge[0])==find(root,edge[1])){

if(can1[0]==-1){

return edge;

}else{

return can1;

}

}else{

root[edge[1]]=edge[0];

}

}

return can2;

}

public int find(int[] root,int p){

int i=p;

while(i!=root[i]){

i=root[i];

}

int j=p;

while(root[j]!=i){

int temp=root[j];

root[j]=i;

j=temp;

}

return i;

}

}

代码解释:

1.使用can1和can2来存某个拥有两个父节点的结点的两条边,如果存在这样的结点,先将can2这条边断开,如果不存在则不做处理。

2.循环加入每条边,判断当前有向图是否形成了环,如果整个遍历过程都没有出现环的话,说明第一步中断开的can2这条边就是我们需要删除的;如果遍历过程中出现了环,并且存在can1和can2两条边,则说明我们第一步中断开的can2不是需要删除的,那么我们直接返回can1就好;如果遍历过程中出现了环并且不存在can1和can2,那么直接返回导致环的这条边就好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值