首页 > 应用开发 > IT综合 > 并查集(UnionFind)技巧总结
type UnionFind struct { count int parent []int } func ctor(n int) UnionFind { uf := UnionFind{ count: n, parent: make([]int, n), } for i := 0; i < n; 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-- }
func findCircleNum(M [][]int) int { n := len(M) uf := ctor(n) // 遍历学生 i, j ,if M[i][j]==1 加入集 for i := 0; i < n; i++ { for j := i + 1; j < n; 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 < n; 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 的时间复杂度为 O(1)O(1) ,所以总的时间复杂度为 O(n2)O(n2)。
(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 < rows; i++ { for j := 0; j < cols; j++ { index := i*cols + j if grid[i][j] == '1' { for _, direction := range directions { newI, newJ := i+direction[0], j+direction[1] if newI < rows && newJ < cols && grid[newI][newJ] == '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 < n; 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 大小的数组空间。
'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 < m; 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 < n; 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 < n; i++ { for j := 0; j < m; j++ { if board[i][j] == 'O' { for _, direction := range directions { newI, newJ := i+direction[0], j+direction[1] if newI < n && newJ < m && board[newI][newJ] == 'O' { uf.union(getIndex(newI, newJ), getIndex(i, j)) } } } } } // 3. 遍历二维矩阵,把不在哨兵集合里的全部填充为 'X' for i := 0; i < n; i++ { for j := 0; j < m; 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 < n; 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. 被围绕的区域。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69984138/viewspace-2727479/ ,如需转载,请注明出处,否则将追究法律责任。