在本问题中, 树指的是一个连通且无环的无向图。
输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, ..., N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。
结果图是一个以边
组成的二维数组。每一个边
的元素是一对[u, v]
,满足 u < v
,表示连接顶点u
和v
的无向图的边。
返回一条可以删去的边,使得结果图是一个有着N个节点的树。如果有多个答案,则返回二维数组中最后出现的边。答案边 [u, v]
应满足相同的格式 u < v
。
示例 1:
输入: [[1,2], [1,3], [2,3]] 输出: [2,3] 解释: 给定的无向图为: 1 / 2 - 3
示例 2:
输入: [[1,2], [2,3], [3,4], [1,4], [1,5]] 输出: [1,4] 解释: 给定的无向图为: 5 - 1 - 2 | | 4 - 3
注意:
- 输入的二维数组大小在 3 到 1000。
- 二维数组中的整数在1到N之间,其中N是输入数组的大小。
并查集问题中的最基本的问题,本题中为了不让这个树成环,需要找出最后一条让它成环的路径。
本题是并查集问题的第一题,介绍一下并查集和它的方法。
定义
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。
举个简单的例子来讲:
现在有几个大家族,每个家族有很多个分支,有N个人,分别为1-N,每个人都有自己的祖先。
现在我想知道 A 和 B是否是一个祖先?
1、首先,每个人都有自己的祖先,所以我们用一个数组来存储A的祖先father[A]
2、每个人一开始,自己是自己的祖先。
3、根据输入的数据,对其祖先进行更新或修改。
4、如果需要判断A和B的祖先是否相同,比较father[A]和father[B]的值就可以了。
本题中,我们也可以把这个树的问题,当作是祖先问题。
以示例1为例:
一开始,每个人的祖先是自己,即
father[1] = 1; father[2] = 2; father[3] = 3;
第一个数据[1,2]输入:
father[2] = 1;
第二个数据[1,3]输入:
father[3] = 1;
第三个数据[2,3]输入,我们发现2和3的祖先已经不是自己了,即已经指派过祖先给它们了。
所以我们分别求一下2和3的祖先。
father[2] = 1;
father[3] = 1;
发现2和3属于同一个祖先,所以2-3之间这条线不能连接,不然就成环了。
那么,如果2和3的祖先不想等的话呢?
举个例子,2的祖先是4,3的祖先是5,那么我们可以让4的祖先等于5来把它们加入到同一个家族里。
这题还可以路径压缩优化一下:
class Solution { int[] family ; public int[] findRedundantConnection(int[][] edges) { family = new int[edges.length+1]; for (int i = 0; i < edges.length+1; i++) { family[i] = i; } for (int i = 0; i < edges.length; i++) { int[] temp = edges[i]; int first = temp[0]; int second = temp[1]; int father1 = getFather(first); int father2 = getFather(second); if(father1==father2){ return temp; }else{ family[father1] = father2; } } return new int[2]; } public int getFather(int i){ int father = family[i]; if(father==i){ return father; }else{ return getFather(father); } } }
原文地址:https://www.cnblogs.com/qinyuguan/p/11509349.html