In this problem, a tree is an undirected graph that is connected and has no cycles.
You are given a graph that started as a tree with n nodes labeled from 1 to 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 graph is represented as an array edges of length n where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi in the graph.
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 input.
Example 1:

Input: edges = [[1,2],[1,3],[2,3]] Output: [2,3]
Example 2:

Input: edges = [[1,2],[2,3],[3,4],[1,4],[1,5]] Output: [1,4]
Constraints:
n == edges.length3 <= n <= 1000edges[i].length == 21 <= ai < bi <= edges.lengthai != bi1. 并查集
- class UF {
- vector<int> id, size;
- public:
- UF(int n): id(n), size(n, 1) {
- iota(id.begin(), id.end(), 0); // iota函数可以把数组初始化为0到n-1
- }
- int find(int p) {
- while (p != id[p]) {
- id[p] = id[id[p]]; // 路径压缩,使得下次查找更快
- p = id[p];
- }
- return p;
- }
- void connect(int p, int q) {
- int i = find(p), j = find(q);
- if (i != j) {
- // 按秩合并:每次合并都把深度较小的集合合并在深度较大的集合下面
- if (size[i] < size[j]) {
- id[i] = j;
- size[j] += size[i];
- } else {
- id[j] = i;
- size[i] += size[j];
- }
- }
- }
- bool isConnected(int p, int q) {
- return find(p) == find(q);
- }
- };
-
- class Solution {
- public:
- vector<int> findRedundantConnection(vector
int >>& edges) { - int n = edges.size();
- UF uf(n + 1);
- for (auto e: edges) {
- int u = e[0], v = e[1];
- if (uf.isConnected(u, v)) {return e;}
- uf.connect(u, v);
- }
- return vector<int>{-1, -1};
- }
- };
2. 粗暴循环打法
- class Solution {
- public:
- vector<int> findRedundantConnection(vector
int >>& edges) { - int n = 0;
- for(const auto &e : edges) {
- n = max(e[0]+1, n);
- n = max(e[1]+1, n);
- }
- parent_ = vector<int>(n);
- for(int i = 0; i < n; ++i) parent_[i] = i;
- for(auto it = edges.begin(); it != edges.end(); ++it) {
- const auto &e = *it;
- if(GetParent(e[0]) == GetParent(e[1])) {
- if(e[0] < e[1]) return {e[0], e[1]};
- else return {e[1], e[0]};
- }
- parent_[GetParent(e[0])] = GetParent(e[1]);
- }
- return {};
- }
- private:
- int GetParent(int x) {
- if(parent_[x] != x) parent_[x] = GetParent(parent_[x]);
- return parent_[x];
- }
- vector<int> parent_;
- };
- class Solution {
- private int[] parent_;
- public int[] findRedundantConnection(int[][] edges) {
- int n = 0;
- for(int[] e : edges) {
- n = Math.max(e[0]+1, n);
- n = Math.max(e[1]+1, n);
- }
- parent_ = new int[n];
- for(int i = 0; i < n; ++i) parent_[i] = i;
- for(int[] e : edges) {
- if (GetParent(e[0]) == GetParent(e[1])) {
- if(e[0] < e[1]) return new int[]{e[0], e[1]};
- else return new int[]{e[1], e[0]};
- }
- parent_[GetParent(e[0])] = GetParent(e[1]);
- }
- return new int[]{};
- }
-
- private int GetParent(int x) {
- if(parent_[x] != x) parent_[x] = GetParent(parent_[x]);
- return parent_[x];
- }
- }