1. 程式人生 > >LeetCode 85. 冗余連接 II

LeetCode 85. 冗余連接 II

arrays span boolean 引導 這就是 als rect 屬於 指向

題目: 

  在本問題中,有根樹指滿足以下條件的有向圖。該樹只有一個根節點,所有其他節點都是該根節點的後繼。每一個節點只有一個父節點,除了根節點沒有父節點。

輸入一個有向圖,該圖由一個有著N個節點 (節點值不重復1, 2, ..., N) 的樹及一條附加的邊構成。附加的邊的兩個頂點包含在1到N中間,這條附加的邊不屬於樹中已存在的邊。

結果圖是一個以組成的二維數組。 每一個 的元素是一對 [u, v],用以表示有向圖中連接頂點 u and v和頂點的邊,其中父節點u是子節點v的一個父節點。

返回一條能刪除的邊,使得剩下的圖是有N個節點的有根樹。若有多個答案,返回最後出現在給定二維數組的答案。

示例:

      輸入: [[1,2], [1,3], [2,3]]
      輸出: [2,3]
      解釋: 給定的有向圖如下:
        1
       /       v   v
      2-->3


      輸入: [[1,2], [2,3], [3,4], [4,1], [1,5]]
      輸出: [4,1]
      解釋: 給定的有向圖如下:
      5 <- 1 -> 2
           ^    |
           |    v
           4 <- 3

題解:
  
在以上題目中有一句比較關鍵的句子 : 該圖由一個有著N個節點 (節點值不重復1, 2, ..., N) 的樹及一條附加的邊構成。附加的邊
的兩個頂點包含在1到N中間,這條附加的邊不屬於樹中已存在的邊。

  這句話其實是引導我們思路的,我們可以知道題目所說的有根樹具有三個性質。第一,有根樹存在入度為0的節點(根節點),第二有根樹除了
根節點其他節點的入度都為1。第三有根樹所有節點都是連通的。
    如若一顆有根樹加上一條邊的話,那麽加上的邊存在以下三種情況:
    1)邊的兩端是同一節點
      判定方式 : 直接看兩遍是否相等
      處理 : 直接可以知道這條邊肯定不是原有的,返回當前邊
    2)兩端不是同一節點,並且被指向的是根節點。
      判定方式 : 如若被指向的那端統計之後出現了所有節點或者不存在入度為2的節點
      處理 : 因為根被指向了後一定會形成環,故而處理的可能性很多(除去環內任意邊),但是需要註意是否存在示例2中的情況,如若除去邊[1,5],就會導致該有根樹不連通,並且依然有環。 因為是否連通使用並查集很容易檢測是否連通
,故而這裏我選擇了直接使用並查集。
    3)兩端不是同一節點,並且被指向的是非根節點。
      判定方式 : 剩下的情況都是3)//存在入度為2的節點
      處理 : 因為存在入度為2的節點,所以在這就是在兩條指向入度為2節點內直接二選一,但是這裏不能隨便選,必須保證如若因為這條邊成環(例如示例一加上一個節點4並且4指向2),也就是 : [[4, 2],[1,2], [1,3], [2,3]]
,這時指向2的一共有兩個節點 4 和 1,這時候如若選擇刪除[1,2]則會導致整張圖不連通,故而需要檢查連通性來選擇刪除兩個節點的哪個,依然使用並查集。
代碼:
 1 int n;
 2     public int[] findRedundantDirectedConnection(int[][] edges) {
 3         this.n = edges.length;
 4         int[] table = new int[n];
 5         Arrays.fill(table, -1);
 6         int other = -1;
 7         for (int i = 0; i < n; i++) {
 8             if (edges[i][0] == edges[i][1]) {
 9                 return edges[i];
10             }
11             int index = edges[i][1] - 1;
12             if (table[index] != -1) {
13                 other = i;
14             } else {
15                 table[index] = i;
16             }
17         }
18         // 如若指向非根
19         if (other != -1) {
20             // 且 如若刪除了後面那個節點 仍然是 連通的。
21             if (this.isConnected(edges, other))
22                 return edges[other];
23             else
24                 return edges[table[edges[other][1] - 1]];
25         }
26         for (int i = n - 1; i >= 0; i--) {
27             //如若除去i還是連通的
28             if (this.isConnected(edges, i)) {
29                 return edges[i];
30             }
31         }
32         return new int[] {};
33     }
34 
35     /**
36      * 若除去第i條邊
37      * 
38      * @param edges
39      * @param i
40      * @return
41      */
42     int[] table;
43 
44     public boolean isConnected(int[][] edges, int i) {
45         this.table = new int[n];
46         for (int j = 0; j < n; j++) {
47             table[j] = j;
48         }
49         for (int j = 0; j < n; j++) {
50             if (j != i)
51                 union(edges[j][0] - 1, edges[j][1] - 1);
52         }
53         boolean flag = true;
54         for (int k = 0; k < n; k++) {
55             if (table[k] == k) {
56                 if (flag) {
57                     flag = false;
58                 } else {
59                     return false;
60                 }
61             }
62         }
63         return true;
64     }
65 
66     public boolean union(int i, int j) {
67         int iIndex = this.find(i);
68         int jIndex = this.find(j);
69         if (iIndex == jIndex) {
70             return false;
71         }
72         table[iIndex] = jIndex;
73         return true;
74     }
75 
76     public int find(int i) {
77         while (table[i] != i) {
78             i = table[i];
79         }
80         return i;
81     }


LeetCode 85. 冗余連接 II