並查集與島嶼問題(leet200)

並查集解決島嶼問題,是一個經典的算法應用。本篇文章旨在幫助大家理解並查集算法,並實現在島嶼問題上的應用。

  • 並查集算法介紹

並查集是一種用於解決動態連通性問題的高效數據結構,爲便於解釋我們以島嶼問題爲例,說明並查集的工作原理。

  • 島嶼問題

給定一個m*n的二位數組,其中1代表陸地,0代表海洋,如果一個陸地塊的上下左右鄰接着另一個陸地塊,則稱它們爲一個島嶼。提問在給定二維數組中有幾個島嶼?(輸入輸出樣例如下)

要解決這個問題很簡單,我們只需要把每一塊陸地計算出它所屬的島嶼標號(分組),然後統計所有標號的數目就是島嶼的數目。在最開始的時候我們認爲每一個陸地塊都是一個島嶼,之後我們通過“並”和“查”兩個操作去不斷地合併陸地塊,並解決問題。

1.“查”算法

def find(x):
    if parent[x]!= x:
       return find(parent[x])
    return parent[x]

但是這樣做有一個問題,隨着不同子集不斷地合併,查詢的複雜度會脫離O1級別,最壞情況下達到鏈表ON級別。這種情況可以使用“路徑壓縮”進行優化,就是把查找過程的所有路徑上的點的parent,改成它們共同的祖先。

def find(x):
    if parent[x]!=x: parent[x]=find[parent[x]]   #遞歸寫法,最終會吧所有點連在根節點上
                                                 #構造一棵扁平的樹
    return parent[x]

還有非遞歸寫法,就是先用一個while循環找到祖先,再把路徑上的點的parent都改成祖先。 

 

 

2."並"算法

def union(x,y):
    xroot, yroot = find(x),find(y)
    if xroot == yroot: return 
    parent[xroot] = yroot
    self.count -= 1

這裏每執行一次並,島嶼數目減1。在實際中我們可以優化並算法,爲每棵樹維護一個深度,每次把深度小的樹併到深度大的樹上。 

for i in range(row):
    for j in range(col):
        if grid[i][j] == '0':
           continue
        index = i*col + j
        if j < col-1 and grid[i][j+1] == '1':
           union(index, index+1)
        if i < row-1 and grid[i+1][j] == '1':
           union(index, index+col)
return self.count

最後遍歷整個二維數組中的陸地,看它右邊和下邊的點需不需要合併,最後返回島嶼數目。

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章