1. 程式人生 > >Leetcode 685. Redundant Connection II

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 };