题目来源
题目描述
题目解析
题目要求:给出一个无向图,要我们找出一条可以删去的边,使得剩余部分是一个树,如果有多个答案,则返回二维数组中最后出现的边。
类似的题目:[LeetCode] 261. Graph Valid Tree 图验证树
分析题意
一棵有n个节点的树有n - 1条边,若再加一条边,则树内必成环,题目要求我们找出这条使得树成环的边;
- 有N个节点,要形成环的话,必须至少有N条边
- 题目中说了只有一条多余的边,那么edges的大小必定是节点数量
这道题的关键在于:选择edges中导致结果图产生环的那条边。
这题本质就是检测图的环,有很多方法,比如并查集、拓扑排序、DFS
并查集
树是一个连通且无环的无向图,在树中多了一条附加的边之后就会出现环,因此附加的边即为导致环出现的边。
可以通过并查集寻找附加的边。初始时,每个节点都属于不同的连通分量。遍历每一条边,判断这条边连接的两个顶点是否属于相同的连通分量。
-
如果两个顶点属于不同的连通分量,则说明在遍历到当前的边之前,这两个顶点之间不连通,因此当前的边不会导致环出现,合并这两个顶点的连通分量。
-
如果两个顶点属于相同的连通分量,则说明在遍历到当前的边之前,这两个顶点之间已经连通,因此当前的边导致环出现,为附加的边,将当前的边作为答案返回
class UnionFind {
private:
int count;
vector<int> parent;
public:
UnionFind(int n) : parent(n) {
int start=1;
count=n-start;
for (int i=start;i<n;i++) {
parent[i]=i;
}
}
/* 查找根节点 */
int findRoot(int x) {
if (x!=parent[x]) {
parent[x]=findRoot(parent[x]);
}
return parent[x];
}
/* 合并操作 */
void unionRoot(int x, int y) {
int root_x=findRoot(x);
int root_y=findRoot(y);
if (root_x != root_y) {
parent[root_x]=root_y;
count--;
}
}
/* 判断x,y是否属于同一连通分量 */
bool isConnect(int x, int y) {
return findRoot(x)==findRoot(y);
}
/* 返回连通分量个数 */
int getCount() {
return count;
}
};
class Solution {
public:
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
int n=edges.size();
UnionFind unionFind(n+1);
for (auto &edge:edges) {
int p=edge[0];
int q=edge[1];
if (unionFind.findRoot(p)!=unionFind.findRoot(q)) {
unionFind.unionRoot(p,q);
} else {
return edge;
}
}
return vector<int>{};
}
};