冗余连接II
相比于冗余连接1把无向图换成有向图,所以需要分类讨论。
有环边:
测试样例:[[1,2],[2,3],[3,1]]
输出:[3,1]
有冲突
测试样例:[[1,2],[1,3],[2,3]]
输出:[2,3]
显然,对于以上两种情况,只存在
1.有环边无冲突
2.无环边有冲突
第一种情况成环的边显然是最后一个输入的边
第二种情况冲突的边就是使一个节点有了第二个父亲节点的边
这两种情况只需要存储那条边并输出即可。
有环边有冲突
测试样例:[[2,1],[3,1],[4,2],[1,4]]
输出:[2,1]
对于测试样例,
[3,1]
是冲突边,它使得节点1拥有两个父节点;
[1,4]
是环边,它使得2->1->4
形成环。
在这个图中我们应该删除的是[2,1]
,而我们要删除的边必然是冲突边的子节点和他的父节点构成的边
题意为:返回一条能删除的边,使得剩下的图是有 n 个节点的有根树。
则删除的边必然从有冲突的顶点的两条边中选:
在样例中是[2,1]
和[3,1]
。
而对于环路来说,删除任意一条边都是等价的,都会使这个环路变成一棵树,所以删除的边必然是冲突顶点和他的父节点构成的边:
在样例中是[2,1]
.
我们利用并查集维护,只记录而不在并查集中连接冲突边和环边。
我们建一棵保存父节点的树,只要不发生冲突就记录,最终可以利用这课树返回有环边有冲突时要删除的边。
解决代码:
class Solution {
public:
vector<int >a;
vector<int >h;
void unionfind(int n)
{
for(int i=0;i<=n;i++)
{
a.push_back(i);
h.push_back(0);
}
}
int find(int x)
{
return x==a[x]? x : a[x]=find(a[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y) return ;
if(h[x]<h[y])
{
a[x]=y;
}
else
{
a[y]=x;
if(h[x]==h[y]) h[x]++;
}
}
bool same(int x,int y)
{
return find(x)==find(y);
}
vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
int n=edges.size();
unionfind(n);
vector<int> num;
vector<int> parent;
for(int i=0;i<=n;i++)
parent.push_back(i);
int conflict=-1;
int circle=-1;
for(int i=0;i<n;i++)
{
int nodex=edges[i][0];
int nodey=edges[i][1];
if(parent[nodey]!=nodey)//冲突 连接两个根
{
conflict=i;
}
else
{
parent[nodey]=nodex;
if(same(nodex,nodey)) circle=i;
else unite(nodex,nodey);
}
}
if(conflict<0) num=edges[circle];
else
{
if(circle<0) num=edges[conflict];
else
{
num.push_back(parent[edges[conflict][1]]);
num.push_back(edges[conflict][1]);
}
}
return num;
}
};