LeetCode题解系列--684. Redundant Connection
2017-10-10 14:36
441 查看
描述
In this problem, a tree is an undirected graph that is connected and has no cycles.The given input is a graph that started as a tree with N nodes (with distinct values 1, 2, …, N), with one additional edge added. The added edge has two different vertices chosen from 1 to N, and was not an edge that already existed.
The resulting graph is given as a 2D-array of edges. Each element of edges is a pair [u, v] with u < v, that represents an undirected edge connecting nodes u and v.
Return an edge that can be removed so that the resulting graph is a tree of N nodes. If there are multiple answers, return the answer that occurs last in the given 2D-array. The answer edge [u, v] should be in the same format, with u < v.
Example 1:
Input: [[1,2], [1,3], [2,3]]
Output: [2,3]
Explanation: The given undirected graph will be like this:
1
/ \
2 - 3
Example 2:
Input: [[1,2], [2,3], [3,4], [1,4], [1,5]]
Output: [1,4]
Explanation: The given undirected graph will be like this:
5 - 1 - 2
| |
4 - 3
Note:
The size of the input 2D-array will be between 3 and 1000.
Every integer represented in the 2D-array will be between 1 and N, where N is the size of the input array.
难度:medium
思路
这道题是一道关于无向图的题目,要求在给出的边中找出一条冗余的边,使得去掉这条边后,整个图仍然是连同的。若有多条边可供选择,则返回最后一条符合条件的边。这题你如果不知道需要的算法,怕是要想很久。不过其实很简单,就是要用到一个叫做并查集的算法。
所谓并查集,其实是指两种对集合的操作,一种是并,一种是查。所谓并,就是将两个集合合并起来,所谓查就是检验两个元素是否在同一个集合中。
实现方式是这样,将所有元素放在一个森林中,同一个集合的元素便是在同一颗树上(不限制树的类型,多叉树)。
实际使用的数据结构,使用一个一维数组A,下标i为森林中的元素,A[i]存储的是其父节点,对于根节点,其父节点为其本身。初始化时为A[i]=i,即使得初始化时每个元素为一颗树。根据这个设定我们就可以得到查操作
int find(int x) { if (set[x] != x) { return find(set[x]); } return set[x]; }
对于并操作,只需要将一颗树的根节点随意接到另一颗树的任意一个节点,两个集合就完成了并操作。
void u(int x, int y) { int xParent = find(x); int yParent = find(y); set[xParent] = yParent; }
怎么样,很简单吧。但是这样的算法会造成树的高度越来越大,还可能造成一颗极不平衡的树,若其一直产生右偏树,则其效率基本与线性表相同。所以需要优化。
优化
前面我们有提到,我们对于树的形状没有要求,那么其实我们可以每增加一个节点都将起接到根节点,这样每次查询都会是常数级别的开销。即将树扁平化,这里就有一个很巧妙的方式来完成这个任务。int find(int x) { if (set[x] != x) { set[x] = find(set[x]); } return set[x]; }
将刚刚使用的find函数进行改造,就可以在每次查询操作时都将树变得更加扁平,而每次并的操作都会调用find函数,所以每次都会将一部分节点直接接到根节点上,起到路径压缩的目的,减少树的层数。
答案
#include <vector>
using namespace std;
class Solution {
private:
vector<int> set;
public:
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
set = vector<int>(edges.size() + 1);
int N = edges.size();
for (int i = 1; i <= N; ++i) {
set[i] = i;
}
for (int i = 0; i < N; ++i) {
if (this->find(edges[i][0]) == this->find(edges[i][1])) {
return edges[i];
} else {
this->u(edges[i][0], edges[i][1]);
}
}
}
int find(int x) { if (set[x] != x) { set[x] = find(set[x]); } return set[x]; }
void u(int x, int y) { int xParent = find(x); int yParent = find(y); set[xParent] = yParent; }
};
点击这里查看更多我的LeetCode答案
参考资料:维基百科-并查集
相关文章推荐
- Leetcode 题解系列(九)
- Leetcode 题解系列(八)
- LeetCode题解系列--215. Kth Largest Element in an Array
- Leetcode 题解系列(十六)
- Leetcode 题解系列(二)
- Leetcode 题解系列(一)
- Leetcode 题解系列(十七)
- LeetCode题解系列--4. Median of Two Sorted Arrays
- Leetcode 题解系列(十)
- Leetcode 题解系列(十四)
- LeetCode题解系列--123. Best Time to Buy and Sell Stock III
- LeetCode题解系列--763. Partition Labels
- Leetcode 题解系列(十一)
- Leetcode 题解系列(三)
- Leetcode 题解系列(十二)
- Leetcode 题解系列(六)
- Leetcode 系列题解(十八)
- LeetCode题解系列--1. Two Sum
- Leetcode 题解系列(七)
- LeetCode题解系列--712. Minimum ASCII Delete Sum for Two Strings