并查集路径压缩_并查集(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' ,因此可使用并查集解決。
代碼實現:
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 大小的數組空間。
總結
參考資料
- 并查集 - 力扣
- 并查集概念及用法分析
總結
以上是生活随笔為你收集整理的并查集路径压缩_并查集(UnionFind)技巧总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tl r402路由器设置_tplink
- 下一篇: 广义线性模型_算法小板报(四)——初探广