[LeetCode] 1192. Critical Connections in a Network 查找集群內的關鍵連接



There are n servers numbered from 0 to n - 1 connected by undirected server-to-server connections forming a network where connections[i] = [ai, bi] represents a connection between servers ai and bi. Any server can reach other servers directly or indirectly through the network.

critical connection is a connection that, if removed, will make some servers unable to reach some other server.

Return all critical connections in the network in any order.

Example 1:

Input: n = 4, connections = [[0,1],[1,2],[2,0],[1,3]]
Output: [[1,3]]
Explanation: [[3,1]] is also accepted.

Example 2:

Input: n = 2, connections = [[0,1]]
Output: [[0,1]]

Constraints:

  • 2 <= n <= 10^5
  • n - 1 <= connections.length <= 10^5
  • 0 <= ai, bi <= n - 1
  • ai != bi
  • There are no repeated connections.

這道題說是有n個服務器互相連接,定義了一種關鍵連接,就是當去掉后,會有一部分服務無法訪問另一些服務。說白了,就是讓求無向圖中的橋,對於求無向圖中的割點或者橋的問題,需要使用塔里安算法 Tarjan's Algorithm。該算法是圖論中非常常用的算法之一,能解決強連通分量,雙連通分量,割點和橋,求最近公共祖先(LCA)等問題,可以參見知乎上的這個貼子。Tarjan 算法是一種深度優先遍歷 Depth-first Search 的算法,而且還帶有一點聯合查找 Union Find 的影子在里面。和一般的 DFS 遍歷不同的是,這里用了一個類似時間戳的概念,就是用一個 time 數組來記錄遍歷到當前結點的時間,初始化為1,每遍歷到一個新的結點,時間值就增加1。這里還用了另一個數組 low,來記錄在能夠訪問到的所有節點中,時間戳最小的值,這樣,在一個環上的結點最終 low 值都會被更新成一個最小值,就好像 Union Find 中同一個群組中都有相同的 root 值一樣。這是非常重要且聰明的處理方式,因為若當前結點是割點的話,即其實橋一頭的端點,當過橋之后,由於不存在其他的路徑相連通(假設整個圖只有一個橋),那么無法再回溯回來的,所以不管橋另一頭的端點 next 的 low 值如何更新,其一定還是會大於 cur 的 low 值的,則橋就找到了。可能干講不好理解,建議看下上面提到的知乎帖子,里面有圖和視頻可以很好的幫助理解。

這里首先根據給定的邊來建立圖的結構,這里使用 HashMap 來建立結點和其所有相連的結點集合之間的映射。對於每條邊,由於是無向圖,則兩個方向都要建立映射,然后就調用遞歸,要傳的參數還真不少,圖結構,當前結點,前一個結點,cnt 值,time 和 low 數組,還有結果 res。在遞歸函數中,首先給當前結點 cur 的 time 和 low 值都賦值為 cnt,然后 cnt 自增1。接下來遍歷和當前結點所有相鄰的結點,若 next 的時間戳為0,表示這個結點沒有被遍歷過,則對該結點調用遞歸,然后用 next 結點的 low 值來更新當前結點的 low 值。若 next 結點已經之前訪問過了,但不是前一個結點,則用 next 的 time 值來更新當前結點的 low 值。若回溯回來之后,next 的 low 值仍然大於 cur 的 time 值,說明這兩個結點之間沒有其他的通路,則一定是個橋,加入到結果 res 中即可,參見代碼如下:


class Solution {
public:
    vector<vector<int>> criticalConnections(int n, vector<vector<int>>& connections) {
        int cnt = 1;
        vector<vector<int>> res;
        vector<int> time(n), low(n);
        unordered_map<int, vector<int>> g;
        for (auto conn : connections) {
            g[conn[0]].push_back(conn[1]);
            g[conn[1]].push_back(conn[0]);
        }
        helper(g, 0, -1, cnt, time, low, res);
        return res;
    }
    void helper(unordered_map<int, vector<int>>& g, int cur, int pre, int& cnt, vector<int>& time, vector<int>& low, vector<vector<int>>& res) {
        time[cur] = low[cur] = cnt++;
        for (int next : g[cur]) {
            if (time[next] == 0) {
                helper(g, next, cur, cnt, time, low, res);
                low[cur] = min(low[cur], low[next]);
            } else if (next != pre) {
                low[cur] = min(low[cur], time[next]);
            }
            if (low[next] > time[cur]) {
                res.push_back({cur, next});
            }
        }
    }
};

Github 同步地址:

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


參考資料:

https://leetcode.com/problems/critical-connections-in-a-network/

https://zhuanlan.zhihu.com/p/101923309

https://leetcode.com/problems/critical-connections-in-a-network/discuss/382638/DFS-detailed-explanation-O(orEor)-solution

https://leetcode.com/problems/critical-connections-in-a-network/discuss/1174196/JS-Python-Java-C%2B%2B-or-Tarjan's-Algorithm-Solution-w-Explanation


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM