Redundant Connection 冗余连接

在本问题中, 树指的是一个连通且无环的无向图。

输入一个图,该图由一个有着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是输入数组的大小。

更新(2017-09-26):
我们已经重新检查了问题描述及测试用例,明确图是无向 图。对于有向图详见冗余连接II。对于造成任何不便,我们深感歉意。

思路:

方法一:采用bfs的思想,每加一个边到节点中就检查是否存在环路,如果存在环路就返回。检测是否存在环路算法如下:

利用bfs的思想,判断当前节点对(比如[1,2])以1为起点,2为终点,是否已存在路径从1开始到2结束。但是这样做时间消耗较大,因为对每一个节点对都要做广度优先遍历,且还要控制避免出现死循环[1,2]和[2,1]。代码如下:

bool hasCircle(int cur,int target, unordered_map> &m,int pre) {
	if (m[cur].count(target)) {
		return true;
	}
	for (auto tmp : m[cur]) {
        		if (tmp == pre) {
			continue;
		}
		if (hasCircle(tmp, target, m, cur)) {
			return true;
		}
	}
	return false;
}
vector findRedundantConnection(vector>& edges) {
	unordered_map> m;
	for (auto edge : edges) {
		if (hasCircle(edge[0], edge[1], m, -1)) {
			return edge;
		}
		m[edge[0]].insert(edge[1]);
		m[edge[1]].insert(edge[0]);
	}
	return {};
}

方法二:

利用union find的思想,用一个邻接表表示相关关系,建立一个对应关系,a[i]=j表示i可以连接到j,具体union find原理深入了解了在做详细解释,这里只解释怎么用。对于任何一个数组对[i,j],如果经过映射关系最后返回的x和y都是相同的值,则证明这组数组对就是待删除的边(这里讲的比较乱,下面给一个例子),首先映射函数如下:

int find(vector &vec, int i) {
	while (vec[i] != -1) {
		i = vec[i];
	}
	return i;
}

映射函数如上如所示,对于题目的例子:

  1
 / \
2 - 3
输入
[1,2]

对数组对每一个数都应用映射函数,则映射函数返回的结果图示为:

  1
 / 
2 

再输入

[1,3]

对于1,映射函数返回2,对于3,映射函数返回3,由于2!=3,所以加到映射关系里a[2]=3,结果更新为:

  1
 / 
2 ——3

再输入

[2,3]

2映射为3,3映射为3,3==3所以[2,3]这个数组对如果加上就会形成环,所以答案是[2,3]。union find换一种思路理解就是通过单向链表的关系,把所有能到达的节点通过链表连接起来,如果这时候数组对的两个值映射返回相同的值,意味着就算不加这个数组对也能实现两个点的连通查找,如果在两个节点间再加这个数组对,就会形成环。

代码如下:

int find(vector &vec, int i) {
	while (vec[i] != -1) {
		i = vec[i];
	}
	return i;
}
vector findRedundantConnection(vector>& edges) {
	vector vec(1001, -1);
	for (auto edge : edges) {
		int x = find(vec, edge[0]);
		int y = find(vec, edge[1]);
		if (x == y) {
			return edge;
		}
		vec[x] = y;
	}
	return {};
}



你可能感兴趣的:(算法)