日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

并查集路径压缩_并查集(UnionFind)技巧总结

發布時間:2023/12/19 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 并查集路径压缩_并查集(UnionFind)技巧总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是并查集

在計算機科學中,并查集是一種樹型的數據結構,用于處理一些不交集(Disjoint Sets)的合并及查詢問題。有一個聯合-查找算法(Union-find Algorithm)定義了兩個用于此數據結構的操作:

  • Find:確定元素屬于哪一個子集。它可以被用來確定兩個元素是否屬于同一子集。
  • Union:將兩個子集合并成同一個集合。

由于支持這兩種操作,一個不相交集也常被稱為聯合-查找數據結構(Union-find Data Structure)或合并-查找集合(Merge-find Set)。

并查集可以解決什么問題

  • 組團、配對
  • 圖的連通性問題
  • 集合的個數
  • 集合中元素的個數

算法模板

type?UnionFind?struct?{
?count??int
?parent?[]int
}

func?ctor(n?int)?UnionFind?{
?uf?:=?UnionFind{
??count:??n,
??parent:?make([]int,?n),
?}
?for?i?:=?0;?i???uf.parent[i]?=?i
?}
?return?uf
}

func?(uf?*UnionFind)?find(p?int)?int?{
?for?p?!=?uf.parent[p]?{
??uf.parent[p]?=?uf.parent[uf.parent[p]]?//?路徑壓縮
??p?=?uf.parent[p]
?}
?return?p
}

func?(uf?*UnionFind)?union(p,?q?int)?{
?rootP,?rootQ?:=?uf.find(p),?uf.find(q)
?if?rootP?==?rootQ?{
??return
?}
?uf.parent[rootP]?=?rootQ
?uf.count--
}

實例

547. 朋友圈

547. 朋友圈

題目分析:

題目求的是有多少個朋友圈,也就是求有集合個數,可用并查集解決。

兩重遍歷所有學生,判斷倆倆是否為朋友,如為朋友將加入到集合中。這里可以通過遍歷二維矩陣的右半邊即可,可降低遍歷數量,從而降低時間復雜度。

代碼實現:

func?findCircleNum(M?[][]int)?int?{
?n?:=?len(M)
?uf?:=?ctor(n)
?//?遍歷學生?i,?j?,if?M[i][j]==1?加入集
?for?i?:=?0;?i???for?j?:=?i?+?1;?j????if?M[i][j]?==?1?{
????uf.union(i,?j)
???}
??}
?}
?//?再返回有多少個集合
?return?uf.count
}

type?UnionFind?struct?{
?parents?[]int
?count???int
}

func?ctor(n?int)?UnionFind?{
?uf?:=?UnionFind{
??parents:?make([]int,?n),
??count:???n,
?}

?for?i?:=?0;?i???uf.parents[i]?=?i
?}

?return?uf
}

func?(uf?*UnionFind)?find(p?int)?int?{
?for?p?!=?uf.parents[p]?{
??uf.parents[p]?=?uf.parents[uf.parents[p]]
??p?=?uf.parents[p]
?}
?return?p
}

func?(uf?*UnionFind)?union(p,?q?int)?bool?{
?rootP,?rootQ?:=?uf.find(p),?uf.find(q)
?if?rootP?==?rootQ?{
??return?false
?}
?uf.parents[rootP]?=?rootQ
?uf.count--
?return?true
}

復雜度分析:

  • 時間復雜度:。兩重遍歷用時 ,uf.union 和 uf.find 的時間復雜度為 ,所以總的時間復雜度為 。
  • 空間復雜度:。需要一個 大小的空間。

200. 島嶼數量

200. 島嶼數量

題目分析:

題目求的是島嶼數量,即集合個數,可用并查集解決。

題目可抽象為遍歷所有網格 (i, j),如果是陸地((i, j) == '1'),則把其右邊的陸地((i+1, j) == '1')和下邊的陸地((i, j+1) == '1')合并到一起;如是水((i, j) == '0'),則把其合并到一個哨兵集合里。最后返回 集合個數 - 1。

注:這里關鍵是對于水的處理,把其合并到一個哨兵集合里,讓水不會單獨存在,從而干擾島嶼個數的判斷。

代碼實現:

func?numIslands(grid?[][]byte)?int?{
?rows?:=?len(grid)
?if?rows?==?0?{
??return?0
?}
?cols?:=?len(grid[0])
?if?cols?==?0?{
??return?0
?}

?uf?:=?ctor(rows*cols?+?1)
?guard := rows * cols //?哨兵:用于作為?'0'?的集合
?directions?:=?[][]int{[]int{0,?1},?[]int{1,?0}}

?for?i?:=?0;?i???for?j?:=?0;?j????index?:=?i*cols?+?j
???if?grid[i][j]?==?'1'?{
????for?_,?direction?:=?range?directions?{
?????newI,?newJ?:=?i+direction[0],?j+direction[1]
?????if?newI?'1'?{
??????newIndex?:=?newI*cols?+?newJ
??????uf.union(index,?newIndex)
?????}
????}
???}?else?{
????uf.union(guard,?index)
???}
??}
?}
?return?uf.count?-?1
}

type?UnionFind?struct?{
?parents?[]int
?count???int
}

func?ctor(n?int)?UnionFind?{
?uf?:=?UnionFind{parents:?make([]int,?n),?count:?n}
?for?i?:=?0;?i???uf.parents[i]?=?i
?}
?return?uf
}

func?(uf?*UnionFind)?find(p?int)?int?{
?for?p?!=?uf.parents[p]?{
??uf.parents[p]?=?uf.parents[uf.parents[p]]
??p?=?uf.parents[p]
?}
?return?p
}

func?(uf?*UnionFind)?union(p,?q?int)?bool?{
?rootP,?rootQ?:=?uf.find(p),?uf.find(q)
?if?rootP?==?rootQ?{
??return?false
?}
?uf.parents[rootP]?=?rootQ
?uf.count--
?return?true
}

復雜度分析:

  • 時間復雜度:,其中 n 和 m 分別表示二維數組的行數和列數。
  • 空間復雜度:。并查集需要 n * m 大小的數組空間。

130. 被圍繞的區域

130. 被圍繞的區域

題目分析:

題目可理解為把邊界上的 'O' 保留,其他都填充為 'X' ,可以把邊界上的 'O' 作為一個集合,不是這個集合的填充為 'X' ,因此可使用并查集解決。

  • 遍歷邊界上的點,把 'O' 合并到一個哨兵集合里。
  • 遍歷二維矩陣里的點,把 'O' 的右和下合并到一起。
  • 遍歷二維矩陣,把不在哨兵集合里的全部填充為 'X'
  • 代碼實現:

    func?solve(board?[][]byte)?{
    ?n?:=?len(board)
    ?if?n?==?0?{
    ??return
    ?}
    ?m?:=?len(board[0])
    ?if?m?==?0?{
    ??return
    ?}
    ?uf?:=?ctor(n*m?+?1)
    ?guard?:=?n?*?m
    ?directions?:=?[][]int{[]int{0,?1},?[]int{1,?0}}

    ?getIndex?:=?func(i,?j?int)?int?{
    ??return?i*m?+?j
    ?}
    ?//?1.?遍歷邊界上的點,把?'O'?合并到一個哨兵集合里。
    ?for?j?:=?0;?j???if?board[0][j]?==?'O'?{
    ???uf.union(getIndex(0,?j),?guard)
    ??}
    ??if?board[n-1][j]?==?'O'?{
    ???uf.union(getIndex(n-1,?j),?guard)
    ??}
    ?}
    ?for?i?:=?0;?i???if?board[i][0]?==?'O'?{
    ???uf.union(getIndex(i,?0),?guard)
    ??}
    ??if?board[i][m-1]?==?'O'?{
    ???uf.union(getIndex(i,?m-1),?guard)
    ??}
    ?}

    ?//?2.?遍歷二維矩陣里的點,把?```'O'```?的右和下合并到一起。
    ?for?i?:=?0;?i???for?j?:=?0;?j????if?board[i][j]?==?'O'?{
    ????for?_,?direction?:=?range?directions?{
    ?????newI,?newJ?:=?i+direction[0],?j+direction[1]
    ?????if?newI?'O'?{
    ??????uf.union(getIndex(newI,?newJ),?getIndex(i,?j))
    ?????}
    ????}
    ???}
    ??}
    ?}

    ?//?3.?遍歷二維矩陣,把不在哨兵集合里的全部填充為?'X'
    ?for?i?:=?0;?i???for?j?:=?0;?j????if?!uf.isConnect(getIndex(i,?j),?guard)?{
    ????board[i][j]?=?'X'
    ???}
    ??}
    ?}
    }

    type?UnionFind?struct?{
    ?parents?[]int
    ?count???int
    }

    func?ctor(n?int)?UnionFind?{
    ?uf?:=?UnionFind{
    ??parents:?make([]int,?n),
    ??count:???n,
    ?}

    ?for?i?:=?0;?i???uf.parents[i]?=?i
    ?}

    ?return?uf
    }

    func?(uf?*UnionFind)?find(p?int)?int?{
    ?for?p?!=?uf.parents[p]?{
    ??uf.parents[p]?=?uf.parents[uf.parents[p]]
    ??p?=?uf.parents[p]
    ?}
    ?return?p
    }

    func?(uf?*UnionFind)?union(p,?q?int)?bool?{
    ?rootP,?rootQ?:=?uf.find(p),?uf.find(q)
    ?if?rootP?==?rootQ?{
    ??return?false
    ?}
    ?uf.parents[rootP]?=?rootQ
    ?uf.count--
    ?return?true
    }

    func?(uf?*UnionFind)?isConnect(p,?q?int)?bool?{
    ?return?uf.find(p)?==?uf.find(q)
    }

    復雜度分析:

    • 時間復雜度:,其中 n 和 m 分別表示二維數組的行數和列數。
    • 空間復雜度:。并查集需要 n * m 大小的數組空間。

    總結

  • 要熟練掌握并查集的模板,要能夠快速寫出來。
  • 要掌握并查集的應用場景。例如組團、配對、圖的連通性問題、集合個數、集合中元素的個數等。
  • 對于二維的問題轉一維解決,例如 200. 島嶼數量 和 130. 被圍繞的區域。
  • 找出元素間的“配對”關系是解決問題的關鍵。例如二維數組,找當前位置與其右和其下配對。例如 200. 島嶼數量 和 130. 被圍繞的區域。
  • 參考資料

    • 并查集 - 力扣
    • 并查集概念及用法分析
    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的并查集路径压缩_并查集(UnionFind)技巧总结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。