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.

Update (2017-09-26):
We have overhauled the problem description + test cases and specified clearly the graph is an undirected graph. For the directedgraph follow up please see Redundant Connection II). We apologize for any inconvenience caused.

这道题给我们了一个无向图,让删掉组成环的最后一条边,其实这道题跟之前那道 Graph Valid Tree 基本没什么区别,三种解法都基本相同。博主觉得老题稍微变一下就是一道新题,而 onsite 遇到原题的概率很小,大多情况下都会稍稍变一下,所以举一反三的能力真的很重要,要完全吃透一道题也不太容易,需要多下功夫。首先来看递归的解法,这种解法的思路是,每加入一条边,就进行环检测,一旦发现了环,就返回当前边。对于无向图,还是用邻接表来保存,建立每个结点和其所有邻接点的映射,由于两个结点之间不算有环,所以要避免这种情况 1->{2}, 2->{1} 的死循环,用一个变量 pre 记录上一次递归的结点,比如上一次遍历的是结点1,那么在遍历结点2的邻接表时,就不会再次进入结点1了,这样有效的避免了死循环,使其能返回正确的结果,参见代码如下:

解法一:

class Solution {
public:
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
unordered_map<int, unordered_set<int>> m;
for (auto edge : edges) {
if (hasCycle(edge[], edge[], m, -)) return edge;
m[edge[]].insert(edge[]);
m[edge[]].insert(edge[]);
}
return {};
}
bool hasCycle(int cur, int target, unordered_map<int, unordered_set<int>>& m, int pre) {
if (m[cur].count(target)) return true;
for (int num : m[cur]) {
if (num == pre) continue;
if (hasCycle(num, target, m, cur)) return true;
}
return false;
}
};

既然递归能做,一般来说迭代也木有问题。但是由于 BFS 的遍历机制和 DFS 不同,所以没法采用利用变量 pre 来避免上面所说的死循环(不是很确定,可能是博主没想出来,有做出来的请在评论区贴上代码),所以采用一个集合来记录遍历过的结点,如果该结点已经遍历过了,那么直接跳过即可,否则就把该结点加入 queue 和集合,继续循环,参见代码如下:

解法二:

class Solution {
public:
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
unordered_map<int, unordered_set<int>> m;
for (auto edge : edges) {
queue<int> q{{edge[]}};
unordered_set<int> s{{edge[]}};
while (!q.empty()) {
auto t = q.front(); q.pop();
if (m[t].count(edge[])) return edge;
for (int num : m[t]) {
if (s.count(num)) continue;
q.push(num);
s.insert(num);
}
}
m[edge[]].insert(edge[]);
m[edge[]].insert(edge[]);
}
return {};
}
};

其实这道题最好的解法使用 Union Find 来做,论坛上清一色的都是用这种解法来做的,像博主用 DFS 和 BFS 这么清新脱俗的方法还真不多:) 其实 Union Find 的核心思想并不是很难理解,首先建立一个长度为 (n+1) 的数组 root,由于这道题并没有明确的说明n是多少,只是说了输入的二位数组的长度不超过 1000,那么n绝对不会超过 2000,加1的原因是由于结点值是从1开始的,而数组是从0开始的,懒得转换了,就多加一位得了。将这个数组都初始化为 -1,有些人喜欢初始化为i,都可以。开始表示每个结点都是一个单独的组,所谓的 Union Find 就是要让结点之间建立关联,比如若 root[1] = 2,就表示结点1和结点2是相连的,root[2] = 3 表示结点2和结点3是相连的,如果此时新加一条边 [1, 3] 的话,我们通过 root[1] 得到2,再通过 root[2] 得到3,说明结点1有另一条路径能到结点3,这样就说明环是存在的;如果没有这条路径,那么要将结点1和结点3关联起来,让 root[1] = 3 即可,参见代码如下:

解法三:

class Solution {
public:
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
vector<int> root(, -);
for (auto edge : edges) {
int x = find(root, edge[]), y = find(root, edge[]);
if (x == y) return edge;
root[x] = y;
}
return {};
}
int find(vector<int>& root, int i) {
while (root[i] != -) {
i = root[i];
}
return i;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/684

类似题目:

Friend Circles

Accounts Merge

Redundant Connection II

Number of Islands II

Graph Valid Tree

Number of Connected Components in an Undirected Graph

Similar String Groups

参考资料:

https://leetcode.com/problems/redundant-connection/

https://leetcode.com/problems/redundant-connection/discuss/112562/My-DFS-and-BSF-solutions

https://leetcode.com/problems/redundant-connection/discuss/107984/10-line-Java-solution-Union-Find.

https://leetcode.com/problems/redundant-connection/discuss/108010/C%2B%2B-solution-using-union-find

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] 684. Redundant Connection 冗余的连接的更多相关文章

  1. LeetCode 684. Redundant Connection 冗余连接(C++/Java)

    题目: In this problem, a tree is an undirected graph that is connected and has no cycles. The given in ...

  2. LN : leetcode 684 Redundant Connection

    lc 684 Redundant Connection 684 Redundant Connection In this problem, a tree is an undirected graph ...

  3. [LeetCode] Redundant Connection 冗余的连接

    In this problem, a tree is an undirected graph that is connected and has no cycles. The given input ...

  4. leetcode 684. Redundant Connection

    We are given a "tree" in the form of a 2D-array, with distinct values for each node. In th ...

  5. [LeetCode] 685. Redundant Connection II 冗余的连接之 II

    In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) f ...

  6. [LeetCode] 685. Redundant Connection II 冗余的连接之二

    In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) f ...

  7. LeetCode 685. Redundant Connection II

    原题链接在这里:https://leetcode.com/problems/redundant-connection-ii/ 题目: In this problem, a rooted tree is ...

  8. 【LeetCode】684. Redundant Connection 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 并查集 日期 题目地址:https://leetco ...

  9. 684. Redundant Connection

    https://leetcode.com/problems/redundant-connection/description/ Use map to do Union Find. class Solu ...

随机推荐

  1. not in和not exists区别

    如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引: 而not extsts 的子查询依然能用到表上的索引. 所以无论那个表大,用not exists都比not in要快. 也就是 ...

  2. Kafka界面管理工具-kafkamanager

    在上一篇文章<Linux安装Kafka>中,已经介绍了如何在Linux安装Kafka,以及Kafka的启动/关闭和创建发话题并产生消息和消费消息.这篇文章就介绍介绍Kafka管理界面(ka ...

  3. 一个JAVA应用启动缓慢问题排查 --来自jdk securerandom 的问候

    开发某个项目过程中,就需求,搭建了一套测试环境.很快完成! 后来代码中加入了许多新功能,会涉及到反复重启,然后就发现了启动特别慢.这给原本功能就不多的应用增添了许多的负担. 我决定改变这一切!找到启动 ...

  4. Python - 数字 - 第六天

    Python 数字(Number) Python 数字数据类型用于存储数值. 数据类型是不允许改变的,这就意味着如果改变数字数据类型的值,将重新分配内存空间. 以下实例在变量赋值时 Number 对象 ...

  5. laravel he stream or file "..laravel-2019-02-14.log" could not be opened: failed to open stream: Permission denied

    错误:The stream or file "/var/www/jianshu/storage/logs/laravel-2019-02-14.log" could not be ...

  6. centos7安装mysql5.7(rpm安装版)

    1.下载mysql5.7的rpm安装包 rpm的mysql包,安装起来简单,解压版的mysql还需要做许多配置,稍有不慎就会出错!!! 下载地址:https://dev.mysql.com/downl ...

  7. RVZicsr指令集

    Riscv中每个硬件线程(hart)有4096个独立地址空间的状态寄存器.我们可以通过Zicsr指令读写csr寄存器.总共有6条csr读写指令,这些指令之前都在RV32I/RV64I基础指令集里面,在 ...

  8. Window平台下的静默下载并安装软件脚本bat

    一,隐藏命令窗口 当我们运行bat脚本的时候,弹出CMD窗口.如果要隐藏窗口可以在bat脚本开头处写一下代码: @echo off if "%1" == "h" ...

  9. linux的ftp操作

    1.查看是否安装 rpm -qa |grep vsftpd 没有输出,表示没有安装 2.查看服务状态 1).service vsftpd status 输出信息 vsftpd is stopped 表 ...

  10. APPIUM 常用API介绍(3)

    1.send_keys send_keys(self, *value): Simulates typing into the element[在元素中模拟输入(开启appium自带的输入法并配置了ap ...