Leetcode 685. Redundant Connection II

Problem:

In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) for which all other nodes are descendants of this node, plus every node has exactly one parent, except for the root node which has no parents.

The given input is a directed graph that started as a rooted tree with N nodes (with distinct values 1, 2, ..., N), with one additional directed 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] that represents a directed edge connecting nodes u and v, where u is a parent of child v.

Return an edge that can be removed so that the resulting graph is a rooted tree of N nodes. If there are multiple answers, return the answer that occurs last in the given 2D-array.

Example 1:

Input: [[1,2], [1,3], [2,3]]
Output: [2,3]
Explanation: The given directed graph will be like this:
  1
 / \
v   v
2-->3

Example 2:

Input: [[1,2], [2,3], [3,4], [4,1], [1,5]]
Output: [4,1]
Explanation: The given directed graph will be like this:
5 <- 1 -> 2
     ^    |
     |    v
     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.

Solution:

  仔细阅读题意,这道题蕴含了两个关键点,一个是每个非根节点只有一个父节点,另一个是不存在环。最开始我的思路是直接使用Union Find,如果发现一个edge[0]和edge[1]有共同的根节点,说明存在环,则返回这个节点,如果发现了某个edge[1]的父节点不是其本身,说明他已经存在了父节点,则返回该节点。但这个思路倒在了这个测试用例上:[[2,1],[3,1],[4,2],[1,4]]。这个测试的答案是[2,1],我们来分析一下为什么上面的算法不适用于这个用例。

     2  ->  1
     ^    / ^
     |  /   |
     4<     3

  通过画图可以发现,这个测试用例包含了以上两种情况,既存在环也存在一个节点有两个父节点。根据前面的逻辑,由于[3,1]导致了两个父节点的存在,所以应该返回[3,1],然而,即使返回[3,1],仍然不能解决存在环的问题,所以我们得另想办法。首先我们需要先找出这两对拥有不同父节点的edge,在这个例子中即[2,1],[3,1],我们命名为first和second。如果不存在,说明这个图中只有环,那就用Union Find直接找到最后一个导致环存在的edge即可。如果存在,那么我们就需要判断first和second哪一条边存在于环中,如果没有环,则输出second。所以,现在的难点在于在有环的情况下,找到存在于环中的那条边。当然我们可以通过遍历这个环找到这条边,这里我们可以用一个很巧妙的办法避免遍历。将second,即第二条导致两个父节点的边删除(不是从数组中删除,而是将其值设置为一个不可能的值,比如[0,0],当然这两条边需要事先保存在两个个变量中),那么这里会存在两种情况,如果删了second不存在环了,那么就说明second就是环中的一条边,返回此边。否则返回第一条边。

Code:

 1 class Solution {
 2 public:
 3     int Find(vector<int> &parent,int target){
 4         if(parent[target] == target)
 5             return target;
 6         return Find(parent,parent[target]);
 7     }
 8     vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
 9         int m = edges.size();
10         vector<int> parent(m+1,0);
11         vector<int> first,second;
12         for(int i = 0;i != m;++i){
13             if(parent[edges[i][1]] == 0)
14                 parent[edges[i][1]] = edges[i][0];
15             else{
16                 first = {parent[edges[i][1]],edges[i][1]};
17                 second = edges[i];
18                 edges[i][1] = 0;
19             }
20         }
21         for(int i = 1;i <= m;++i)
22             parent[i] = i;
23         for(int i = 0;i != m;++i){
24             if(edges[i][1] == 0) continue;
25             int px = Find(parent,edges[i][0]);
26             int py = Find(parent,edges[i][1]);
27             if(px == py){
28                 if(first.empty())
29                     return edges[i];
30                 else
31                     return first;
32             }
33             else
34                 parent[edges[i][1]] = edges[i][0];
35         }
36         return second;
37     }
38 };

猜你喜欢

转载自www.cnblogs.com/haoweizh/p/10194808.html