有向图冗余连接题解
使用并查集解决leetcode 685与686题的无向图冗余连接、有向图冗余连接问题
无向图冗余连接
并查集解法:遍历所有edges, 将边的两端节点合并到一个集合中;如果两个节点都已经在集合中导致合并失败, 则说明找到环路,输出当前边;
class Solution {
public:
class UnionFind {
public:
unordered_map<int, int> f;
int find(int x) {
if (f[x] == x) return x;
return f[x] = find(f[x]);
}
int merge(int a, int b) {
int fa = find(a), fb = find(b);
if (fa == fb) return 0;
f[fb] = fa;
return 1;
}
};
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
UnionFind uf;
for (int i = 0; i < edges.size(); i++) {
int u = edges[i][0], v = edges[i][1];
if (!uf.f.count(u)) uf.f[u] = u;
if (!uf.f.count(v)) uf.f[v] = v;
if (!uf.merge(u, v)) {
vector<int> ans{u, v};
return ans;
}
}
return vector<int>();
}
};
有向图冗余连接
题目中的图有两种约束, 1.存在一个没有父节点的根节点 2.除了根节点每个节点只有一个父节点
此图仅存在两种对立情况: 1.所有节点都只有一个父节点,意味这多余的边指向根节点 2. 存在一个节点有2个父节点
哈希表+并查集解法步骤:
1.遍历edges,先用哈希表的性质, 判断有没有某个节点存在两个父节点, 如果有则用flag标记该节点下标,否则设为-1;
2.再次遍历edges构建并查集, 若没有一个节点存在2个父节点,则按无向图方法输出多余边;若不满足约束2,跳过指向被标记的节点的边,同时保存该边起点;
3.扫描保存的2个起点, 其中一条边的两节点必然已经存在于并查集中,将构成环路,判断不能合并成功,则此边就是多余边
提交代码
class Solution {
public:
class UnionFind {
public:
unordered_map<int, int> f;
int find(int x) {
if (f[x] == x) return x;
return f[x] = find(f[x]);
}
int merge(int a, int b) {
int fa = find(a), fb = find(b);
if (fa == fb) return 0;
f[fb] = fa;
return 1;
}
};
vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
UnionFind uf;
vector<int> m;
int flag = -1;
/****初始化并查集,记录存在多余父节点的节点下标*****/
for (int i = 0; i < edges.size(); i++) {
int v = edges[i][1];
if (!uf.f.count(v)) {
uf.f[v] = v;
}
else {
flag = v;
}
}
/****合并节点*****/
for (int i = 0; i < edges.size(); i++) {
int u = edges[i][0], v = edges[i][1];
if (v == flag) {
m.push_back(u);
continue;
}
if (!uf.merge(u, v) && flag == -1) {
vector<int> ans{u, v};
return ans;
}
}
/****对多余父节点情况单独处理*****/
for (int i = 0; i < 2; i++) {
if (!uf.merge(m[i], flag)) {
vector<int> ans{m[i], flag};
return ans;
}
}
return vector<int>();
}
};