1. 程式人生 > 其它 >[leetcode每日一題2021/1/13]684. 冗餘連線

[leetcode每日一題2021/1/13]684. 冗餘連線

技術標籤:演算法leetcode演算法

冗餘連線

題目來源於leetcode,解法和思路僅代表個人觀點。傳送門
難度:中等

題目

在本問題中, 樹指的是一個連通且無環的無向圖。

輸入一個圖,該圖由一個有著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是輸入陣列的大小。

思路

思路與此題類似
並查集入門-990. 等式方程的可滿足性

並查集

正常思路:選擇一條邊去掉,使得該圖的連通分量不變。但是如果這樣程式設計的話,每次用dfs遍歷該圖,會試得時間複雜度

大大提高。我們可以把思路顛倒一下。

遍歷edges陣列,構建一個圖,使得其連通分量為1
檢查兩個頂點是否在同一個集合中
否:合併兩個頂點所在的集合
是:返回該邊作為答案(由於圖有N個頂點,第一條出現的邊,就是二維陣列中最後出現的答案)


該題,使用並查集的特點:無向圖的連通性

程式碼

class Solution {
public:
    //構建並查集
    class UnionFind{
    public:
        vector<int> parent;
        UnionFind(int n){
            parent.resize(n);
for(int i=0;i<n;i++){ parent[i] = i; } } //合併 兩個頂點所在的集合 void join(int x,int y){ int rootX = find(x); int rootY = find(y); // x -> y parent[rootX] = rootY; } //查詢一個頂點的 父節點 int find(int x){ while(parent[x] != x){ //路徑壓縮 parent[x] = parent[parent[x]]; x = parent[x]; } return x; } //判斷兩個頂點是否在同一個集合中 bool isConnected(int x,int y){ return find(x) == find(y); } }; vector<int> findRedundantConnection(vector<vector<int>>& edges) { vector<int> ans(2); //依次取陣列中的邊,利用並查集歸併 int N = edges.size(); UnionFind unionFind(N+1); for(int i=0;i<N;i++){ int x = edges[i][0]; int y = edges[i][1]; if(!unionFind.isConnected(x,y)){ //如果不在同一個集合中,就將兩個集合合併 unionFind.join(x,y); }else{ //如果在同一個集合中,就得出答案 ans[0] = x; ans[1] = y; } } return ans; } };

演算法複雜度

引自-官方題解

時間複雜度: O(NlogN),其中 N 是圖中的節點個數。需要遍歷圖中的 N 條邊,對於每條邊,需要對兩個節點查詢祖先,如果兩個節點的祖先不同則需要進行合併,需要進行 2 次查詢和最多 1 次合併。一共需要進行 2N 次查詢和最多 N 次合併,因此總時間複雜度是 O(2NlogN)=O(NlogN)。這裡的並查集使用了路徑壓縮,但是沒有使用按秩合併,最壞情況下的時間複雜度是O(NlogN),平均情況下的時間複雜度依然是O(Nα(N)),其中 α 為阿克曼函式的反函式,α(N) 可以認為是一個很小的常數。
空間複雜度: O(N),其中 N 是圖中的節點個數。使用陣列parent 記錄每個節點的祖先。
在這裡插入圖片描述