周賽345。又是沒有hard的周賽,真的每次碰到這種排名都會很慘。

題目

輸入整數n,代表有個n節點的無向圖,編號分別從0~n-1。
輸入二維整數陣列edges,其中edges[i] = [ai, bi],代表ai和bi之間存在一條邊。

求有多少完全連通塊

若一個子圖中任意兩點之間都存在路徑,且不與子圖外的節點共享邊,則稱為連通塊
若一個連通塊之間任意兩點都存在邊,則稱為完全連通塊

解法

一個完全連通塊若有v個節點,則每個節點都必須連接其於v-1個節點,共有v*(v-1)條邊。但邊是無向的,[a,b]和[b,a]視為同一條,所以實際上是v*(v-1)/2條邊。

首先建圖,維護每個節點i的鄰接點,同時可以知道有幾條邊。
撰寫一個dfs(i)函數,計算一個連通塊中的節點和邊數。

遍歷每個節點,若還沒訪問過,則代表是一個全新的連通塊,則進行dfs求出節點數v以及邊數e。
如果去重後的邊數正好為上面提到的v*(v-1)/2,代表是完全連通塊,答案加1。

時間複雜度O(n + M),其中M為edges大小。
空間複雜度O(n + M)。

class Solution:
    def countCompleteComponents(self, n: int, edges: List[List[int]]) -> int:
        g=[[] for _ in range(n)]
        for a,b in edges:
            g[a].append(b)
            g[b].append(a)
            
        vis=[False]*n
        
        def dfs(i):
            nonlocal e,v
            vis[i]=True
            v+=1
            e+=len(g[i])
            for j in g[i]:
                if not vis[j]:
                    dfs(j)
        
        ans=0
        for i in range(n):
            if not vis[i]:
                e=v=0
                dfs(i)
                if e==v*(v-1): # e//2 == v*(v-1)//2
                    ans+=1
            
        return ans