使用并查集模板

This commit is contained in:
YDZ
2019-08-22 21:45:57 +08:00
parent 2ad461faaa
commit 4474714996
16 changed files with 183 additions and 205 deletions

View File

@ -1,5 +1,9 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 map时间复杂度 O(n)
func longestConsecutive(nums []int) int {
res, numMap := 0, map[int]int{}
@ -37,8 +41,8 @@ func longestConsecutive1(nums []int) int {
if len(nums) == 0 {
return 0
}
numMap, countMap, lcs, uf := map[int]int{}, map[int]int{}, 0, UnionFind{}
uf.init(len(nums))
numMap, countMap, lcs, uf := map[int]int{}, map[int]int{}, 0, template.UnionFind{}
uf.Init(len(nums))
for i := 0; i < len(nums); i++ {
countMap[i] = 1
}
@ -48,14 +52,14 @@ func longestConsecutive1(nums []int) int {
}
numMap[nums[i]] = i
if _, ok := numMap[nums[i]+1]; ok {
uf.union(i, numMap[nums[i]+1])
uf.Union(i, numMap[nums[i]+1])
}
if _, ok := numMap[nums[i]-1]; ok {
uf.union(i, numMap[nums[i]-1])
uf.Union(i, numMap[nums[i]-1])
}
}
for key := range countMap {
parent := uf.find(key)
parent := uf.Find(key)
if parent != key {
countMap[parent]++
}

View File

@ -1,30 +1,34 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 并查集
func solve(board [][]byte) {
if len(board) == 0 {
return
}
m, n := len(board[0]), len(board)
uf := UnionFind{}
uf.init(n*m + 1) // 特意多一个特殊点用来标记
uf := template.UnionFind{}
uf.Init(n*m + 1) // 特意多一个特殊点用来标记
for i := 0; i < n; i++ {
for j := 0; j < m; j++ {
if (i == 0 || i == n-1 || j == 0 || j == m-1) && board[i][j] == 'O' { //棋盘边缘上的 'O' 点
uf.union(i*m+j, n*m)
uf.Union(i*m+j, n*m)
} else if board[i][j] == 'O' { //棋盘非边缘上的内部的 'O' 点
if board[i-1][j] == 'O' {
uf.union(i*m+j, (i-1)*m+j)
uf.Union(i*m+j, (i-1)*m+j)
}
if board[i+1][j] == 'O' {
uf.union(i*m+j, (i+1)*m+j)
uf.Union(i*m+j, (i+1)*m+j)
}
if board[i][j-1] == 'O' {
uf.union(i*m+j, i*m+j-1)
uf.Union(i*m+j, i*m+j-1)
}
if board[i][j+1] == 'O' {
uf.union(i*m+j, i*m+j+1)
uf.Union(i*m+j, i*m+j+1)
}
}
@ -32,7 +36,7 @@ func solve(board [][]byte) {
}
for i := 0; i < n; i++ {
for j := 0; j < m; j++ {
if uf.find(i*m+j) != uf.find(n*m) {
if uf.Find(i*m+j) != uf.Find(n*m) {
board[i][j] = 'X'
}
}

View File

@ -9,7 +9,7 @@ package leetcode
* }
*/
// 解法一
// 解法一 递归
func preorderTraversal(root *TreeNode) []int {
res := []int{}
if root != nil {
@ -26,7 +26,7 @@ func preorderTraversal(root *TreeNode) []int {
return res
}
// 解法二
// 解法二 递归
func preorderTraversal1(root *TreeNode) []int {
var result []int
preorder(root, &result)
@ -40,3 +40,26 @@ func preorder(root *TreeNode, output *[]int) {
preorder(root.Right, output)
}
}
// 解法三 非递归,用栈模拟递归过程
func preorderTraversal2(root *TreeNode) []int {
if root == nil {
return []int{}
}
stack, res := []*TreeNode{}, []int{}
stack = append(stack, root)
for len(stack) != 0 {
node := stack[len(stack)-1]
stack = stack[:len(stack)-1]
if node != nil {
res = append(res, node.Val)
}
if node.Right != nil {
stack = append(stack, node.Right)
}
if node.Left != nil {
stack = append(stack, node.Left)
}
}
return res
}

View File

@ -1,72 +1,26 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 并查集
// UnionFind defind
type UnionFind struct {
parent, rank []int
count int
}
func (uf *UnionFind) init(n int) {
uf.count = n
uf.parent = make([]int, n)
uf.rank = make([]int, n)
for i := range uf.parent {
uf.parent[i] = i
}
}
func (uf *UnionFind) find(p int) int {
root := p
for root != uf.parent[root] {
root = uf.parent[root]
}
// compress path
for p != uf.parent[p] {
tmp := uf.parent[p]
uf.parent[p] = root
p = tmp
}
return root
}
func (uf *UnionFind) union(p, q int) {
proot := uf.find(p)
qroot := uf.find(q)
if proot == qroot {
return
}
if uf.rank[qroot] > uf.rank[proot] {
uf.parent[proot] = qroot
} else {
uf.parent[qroot] = proot
if uf.rank[proot] == uf.rank[qroot] {
uf.rank[proot]++
}
}
uf.count--
}
func (uf *UnionFind) totalCount() int {
return uf.count
}
func findCircleNum(M [][]int) int {
n := len(M)
if n == 0 {
return 0
}
uf := UnionFind{}
uf.init(n)
uf := template.UnionFind{}
uf.Init(n)
for i := 0; i < n; i++ {
for j := 0; j <= i; j++ {
if M[i][j] == 1 {
uf.union(i, j)
uf.Union(i, j)
}
}
}
return uf.count
return uf.TotalCount()
}
// 解法二 FloodFill DFS 暴力解法

View File

@ -1,14 +1,18 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
)
func findRedundantConnection(edges [][]int) []int {
if len(edges) == 0 {
return []int{}
}
uf, res := UnionFind{}, []int{}
uf.init(len(edges) + 1)
uf, res := template.UnionFind{}, []int{}
uf.Init(len(edges) + 1)
for i := 0; i < len(edges); i++ {
if uf.find(edges[i][0]) != uf.find(edges[i][1]) {
uf.union(edges[i][0], edges[i][1])
if uf.Find(edges[i][0]) != uf.Find(edges[i][1]) {
uf.Union(edges[i][0], edges[i][1])
} else {
res = append(res, edges[i][0])
res = append(res, edges[i][1])

View File

@ -1,11 +1,15 @@
package leetcode
import "sort"
import (
"sort"
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 并查集优化搜索解法
func accountsMerge(accounts [][]string) (r [][]string) {
uf := UnionFind{}
uf.init(len(accounts))
uf := template.UnionFind{}
uf.Init(len(accounts))
// emailToID 将所有的 email 邮箱都拆开,拆开与 id(数组下标) 对应
// idToName 将 id(数组下标) 与 name 对应
// idToEmails 将 id(数组下标) 与整理好去重以后的 email 组对应
@ -15,13 +19,13 @@ func accountsMerge(accounts [][]string) (r [][]string) {
for i := 1; i < len(acc); i++ {
pid, ok := emailToID[acc[i]]
if ok {
uf.union(id, pid)
uf.Union(id, pid)
}
emailToID[acc[i]] = id
}
}
for email, id := range emailToID {
pid := uf.find(id)
pid := uf.Find(id)
idToEmails[pid] = append(idToEmails[pid], email)
}
for id, emails := range idToEmails {
@ -37,8 +41,8 @@ func accountsMerge1(accounts [][]string) [][]string {
if len(accounts) == 0 {
return [][]string{}
}
uf, res, visited := UnionFind{}, [][]string{}, map[int]bool{}
uf.init(len(accounts))
uf, res, visited := template.UnionFind{}, [][]string{}, map[int]bool{}
uf.Init(len(accounts))
for i := 0; i < len(accounts); i++ {
for j := i + 1; j < len(accounts); j++ {
if accounts[i][0] == accounts[j][0] {
@ -55,7 +59,7 @@ func accountsMerge1(accounts [][]string) [][]string {
}
}
if flag {
uf.union(i, j)
uf.Union(i, j)
}
}
}
@ -66,7 +70,7 @@ func accountsMerge1(accounts [][]string) [][]string {
}
emails, account, tmpMap := accounts[i][1:], []string{accounts[i][0]}, map[string]string{}
for j := i + 1; j < len(accounts); j++ {
if uf.find(j) == uf.find(i) {
if uf.Find(j) == uf.Find(i) {
visited[j] = true
for _, v := range accounts[j][1:] {
tmpMap[v] = v

View File

@ -1,18 +1,22 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
)
func minSwapsCouples(row []int) int {
if len(row)&1 == 1 {
return 0
}
uf := UnionFind{}
uf.init(len(row))
uf := template.UnionFind{}
uf.Init(len(row))
for i := 0; i < len(row)-1; i = i + 2 {
uf.union(i, i+1)
uf.Union(i, i+1)
}
for i := 0; i < len(row)-1; i = i + 2 {
if uf.find(row[i]) != uf.find(row[i+1]) {
uf.union(row[i], row[i+1])
if uf.Find(row[i]) != uf.Find(row[i+1]) {
uf.Union(row[i], row[i+1])
}
}
return len(row)/2 - uf.count
return len(row)/2 - uf.TotalCount()
}

View File

@ -1,5 +1,9 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 DFS + 二分
func swimInWater(grid [][]int) int {
row, col, flags, minWait, maxWait := len(grid), len(grid[0]), make([][]int, len(grid)), 0, 0
@ -40,19 +44,19 @@ func addFlags(grid [][]int, flags [][]int, flag int, row int, col int) {
// 解法二 并查集(并不是此题的最优解)
func swimInWater1(grid [][]int) int {
n, uf, res := len(grid), UnionFind{}, 0
uf.init(n * n)
for uf.find(0) != uf.find(n*n-1) {
n, uf, res := len(grid), template.UnionFind{}, 0
uf.Init(n * n)
for uf.Find(0) != uf.Find(n*n-1) {
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
if grid[i][j] > res {
continue
}
if i < n-1 && grid[i+1][j] <= res {
uf.union(i*n+j, i*n+j+n)
uf.Union(i*n+j, i*n+j+n)
}
if j < n-1 && grid[i][j+1] <= res {
uf.union(i*n+j, i*n+j+1)
uf.Union(i*n+j, i*n+j+1)
}
}
}

View File

@ -1,11 +1,15 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
)
func hitBricks(grid [][]int, hits [][]int) []int {
if len(hits) == 0 {
return []int{}
}
uf, m, n, res, oriCount := UnionFindCount{}, len(grid), len(grid[0]), make([]int, len(hits)), 0
uf.init(m*n + 1)
uf, m, n, res, oriCount := template.UnionFindCount{}, len(grid), len(grid[0]), make([]int, len(hits)), 0
uf.Init(m*n + 1)
// 先将要打掉的砖块染色
for _, hit := range hits {
if grid[hit[0]][hit[1]] == 1 {
@ -19,13 +23,13 @@ func hitBricks(grid [][]int, hits [][]int) []int {
}
}
}
oriCount = uf.count[uf.find(m*n)]
oriCount = uf.Count()[uf.Find(m*n)]
for i := len(hits) - 1; i >= 0; i-- {
if grid[hits[i][0]][hits[i][1]] == 2 {
grid[hits[i][0]][hits[i][1]] = 1
getUnionFindFromGrid(grid, hits[i][0], hits[i][1], uf)
}
nowCount := uf.count[uf.find(m*n)]
nowCount := uf.Count()[uf.Find(m*n)]
if nowCount-oriCount > 0 {
res[i] = nowCount - oriCount - 1
} else {
@ -40,71 +44,16 @@ func isInGrid(grid [][]int, x, y int) bool {
return x >= 0 && x < len(grid) && y >= 0 && y < len(grid[0])
}
func getUnionFindFromGrid(grid [][]int, x, y int, uf UnionFindCount) {
func getUnionFindFromGrid(grid [][]int, x, y int, uf template.UnionFindCount) {
m, n := len(grid), len(grid[0])
if x == 0 {
uf.union(m*n, x*n+y)
uf.Union(m*n, x*n+y)
}
for i := 0; i < 4; i++ {
nx := x + dir[i][0]
ny := y + dir[i][1]
if isInGrid(grid, nx, ny) && grid[nx][ny] == 1 {
uf.union(nx*n+ny, x*n+y)
uf.Union(nx*n+ny, x*n+y)
}
}
}
// UnionFindCount define
type UnionFindCount struct {
parent, count []int
}
func (uf *UnionFindCount) init(n int) {
uf.parent = make([]int, n)
uf.count = make([]int, n)
for i := range uf.parent {
uf.parent[i] = i
uf.count[i] = 1
}
}
func (uf *UnionFindCount) find(p int) int {
root := p
for root != uf.parent[root] {
root = uf.parent[root]
}
return root
}
// 不进行秩压缩,时间复杂度爆炸,太高了
// func (uf *UnionFindCount) union(p, q int) {
// proot := uf.find(p)
// qroot := uf.find(q)
// if proot == qroot {
// return
// }
// if proot != qroot {
// uf.parent[proot] = qroot
// uf.count[qroot] += uf.count[proot]
// }
// }
func (uf *UnionFindCount) union(p, q int) {
proot := uf.find(p)
qroot := uf.find(q)
if proot == qroot {
return
}
if proot == len(uf.parent)-1 {
//proot is root
} else if qroot == len(uf.parent)-1 {
// qroot is root, always attach to root
proot, qroot = qroot, proot
} else if uf.count[qroot] > uf.count[proot] {
proot, qroot = qroot, proot
}
//set relation[0] as parent
uf.parent[qroot] = proot
uf.count[proot] += uf.count[qroot]
}

View File

@ -1,16 +1,20 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
)
func numSimilarGroups(A []string) int {
uf := UnionFind{}
uf.init(len(A))
uf := template.UnionFind{}
uf.Init(len(A))
for i := 0; i < len(A); i++ {
for j := i + 1; j < len(A); j++ {
if isSimilar(A[i], A[j]) {
uf.union(i, j)
uf.Union(i, j)
}
}
}
return uf.totalCount()
return uf.TotalCount()
}
func isSimilar(a, b string) bool {

View File

@ -1,28 +1,32 @@
package leetcode
import "math"
import (
"math"
"github.com/halfrost/LeetCode-Go/template"
)
func minMalwareSpread(graph [][]int, initial []int) int {
if len(initial) == 0 {
return 0
}
uf, minIndex, count, countMap := UnionFind{}, 0, math.MinInt64, map[int]int{}
uf.init(len(graph))
uf, minIndex, count, countMap := template.UnionFind{}, 0, math.MinInt64, map[int]int{}
uf.Init(len(graph))
for i := range graph {
for j := range graph[i] {
if i == j {
break
}
if graph[i][j] == 1 {
uf.union(i, j)
uf.Union(i, j)
}
}
}
for i := 0; i < len(graph); i++ {
countMap[uf.find(i)]++
countMap[uf.Find(i)]++
}
for _, v := range initial {
tmp := countMap[uf.find(v)]
tmp := countMap[uf.Find(v)]
if count == tmp && minIndex > v {
minIndex = v
}

View File

@ -1,34 +1,38 @@
package leetcode
import "math"
import (
"math"
"github.com/halfrost/LeetCode-Go/template"
)
func minMalwareSpread2(graph [][]int, initial []int) int {
if len(initial) == 0 {
return 0
}
uf, minIndex, count, countMap, malwareMap, infectMap := UnionFind{}, initial[0], math.MinInt64, map[int]int{}, map[int]int{}, map[int]map[int]int{}
uf, minIndex, count, countMap, malwareMap, infectMap := template.UnionFind{}, initial[0], math.MinInt64, map[int]int{}, map[int]int{}, map[int]map[int]int{}
for _, v := range initial {
malwareMap[v]++
}
uf.init(len(graph))
uf.Init(len(graph))
for i := range graph {
for j := range graph[i] {
if i == j {
break
}
if graph[i][j] == 1 && malwareMap[i] == 0 && malwareMap[j] == 0 {
uf.union(i, j)
uf.Union(i, j)
}
}
}
for i := 0; i < len(graph); i++ {
countMap[uf.find(i)]++
countMap[uf.Find(i)]++
}
// 记录每个集合和直接相邻病毒节点的个数
for _, i := range initial {
for j := 0; j < len(graph); j++ {
if malwareMap[j] == 0 && graph[i][j] == 1 {
p := uf.find(j)
p := uf.Find(j)
if _, ok := infectMap[p]; ok {
infectMap[p][i] = i
} else {
@ -46,7 +50,7 @@ func minMalwareSpread2(graph [][]int, initial []int) int {
for i, v := range infectMap {
// 找出只和一个病毒节点相连通的
if len(v) == 1 {
tmp := countMap[uf.find(i)]
tmp := countMap[uf.Find(i)]
keys := []int{}
for k := range v {
keys = append(keys, k)

View File

@ -1,22 +1,26 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
)
func removeStones(stones [][]int) int {
if len(stones) <= 1 {
return 0
}
uf, rowMap, colMap := UnionFind{}, map[int]int{}, map[int]int{}
uf.init(len(stones))
uf, rowMap, colMap := template.UnionFind{}, map[int]int{}, map[int]int{}
uf.Init(len(stones))
for i := 0; i < len(stones); i++ {
if _, ok := rowMap[stones[i][0]]; ok {
uf.union(rowMap[stones[i][0]], i)
uf.Union(rowMap[stones[i][0]], i)
} else {
rowMap[stones[i][0]] = i
}
if _, ok := colMap[stones[i][1]]; ok {
uf.union(colMap[stones[i][1]], i)
uf.Union(colMap[stones[i][1]], i)
} else {
colMap[stones[i][1]] = i
}
}
return len(stones) - uf.totalCount()
return len(stones) - uf.TotalCount()
}

View File

@ -1,51 +1,55 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
)
// 解法一 并查集 UnionFind
func largestComponentSize(A []int) int {
maxElement, uf, countMap, res := 0, UnionFind{}, map[int]int{}, 1
maxElement, uf, countMap, res := 0, template.UnionFind{}, map[int]int{}, 1
for _, v := range A {
maxElement = max(maxElement, v)
}
uf.init(maxElement + 1)
uf.Init(maxElement + 1)
for _, v := range A {
for k := 2; k*k <= v; k++ {
if v%k == 0 {
uf.union(v, k)
uf.union(v, v/k)
uf.Union(v, k)
uf.Union(v, v/k)
}
}
}
for _, v := range A {
countMap[uf.find(v)]++
res = max(res, countMap[uf.find(v)])
countMap[uf.Find(v)]++
res = max(res, countMap[uf.Find(v)])
}
return res
}
// 解法二 UnionFindCount
func largestComponentSize1(A []int) int {
uf, factorMap := UnionFindCount{}, map[int]int{}
uf.init(len(A))
uf, factorMap := template.UnionFindCount{}, map[int]int{}
uf.Init(len(A))
for i, v := range A {
for k := 2; k*k <= v; k++ {
if v%k == 0 {
if _, ok := factorMap[k]; !ok {
factorMap[k] = i
} else {
uf.union(i, factorMap[k])
uf.Union(i, factorMap[k])
}
if _, ok := factorMap[v/k]; !ok {
factorMap[v/k] = i
} else {
uf.union(i, factorMap[v/k])
uf.Union(i, factorMap[v/k])
}
}
}
if _, ok := factorMap[v]; !ok {
factorMap[v] = i
} else {
uf.union(i, factorMap[v])
uf.Union(i, factorMap[v])
}
}
return uf.maxUnionCount
return uf.MaxUnionCount()
}

View File

@ -1,34 +1,38 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
)
func regionsBySlashes(grid []string) int {
size := len(grid)
uf := UnionFind{}
uf.init(4 * size * size)
uf := template.UnionFind{}
uf.Init(4 * size * size)
for i := 0; i < size; i++ {
for j := 0; j < size; j++ {
switch grid[i][j] {
case '\\':
uf.union(getFaceIdx(size, i, j, 0), getFaceIdx(size, i, j, 1))
uf.union(getFaceIdx(size, i, j, 2), getFaceIdx(size, i, j, 3))
uf.Union(getFaceIdx(size, i, j, 0), getFaceIdx(size, i, j, 1))
uf.Union(getFaceIdx(size, i, j, 2), getFaceIdx(size, i, j, 3))
case '/':
uf.union(getFaceIdx(size, i, j, 0), getFaceIdx(size, i, j, 3))
uf.union(getFaceIdx(size, i, j, 2), getFaceIdx(size, i, j, 1))
uf.Union(getFaceIdx(size, i, j, 0), getFaceIdx(size, i, j, 3))
uf.Union(getFaceIdx(size, i, j, 2), getFaceIdx(size, i, j, 1))
case ' ':
uf.union(getFaceIdx(size, i, j, 0), getFaceIdx(size, i, j, 1))
uf.union(getFaceIdx(size, i, j, 2), getFaceIdx(size, i, j, 1))
uf.union(getFaceIdx(size, i, j, 2), getFaceIdx(size, i, j, 3))
uf.Union(getFaceIdx(size, i, j, 0), getFaceIdx(size, i, j, 1))
uf.Union(getFaceIdx(size, i, j, 2), getFaceIdx(size, i, j, 1))
uf.Union(getFaceIdx(size, i, j, 2), getFaceIdx(size, i, j, 3))
}
if i < size-1 {
uf.union(getFaceIdx(size, i, j, 2), getFaceIdx(size, i+1, j, 0))
uf.Union(getFaceIdx(size, i, j, 2), getFaceIdx(size, i+1, j, 0))
}
if j < size-1 {
uf.union(getFaceIdx(size, i, j, 1), getFaceIdx(size, i, j+1, 3))
uf.Union(getFaceIdx(size, i, j, 1), getFaceIdx(size, i, j+1, 3))
}
}
}
count := 0
for i := 0; i < 4*size*size; i++ {
if uf.find(i) == i {
if uf.Find(i) == i {
count++
}
}

View File

@ -1,19 +1,23 @@
package leetcode
import (
"github.com/halfrost/LeetCode-Go/template"
)
func equationsPossible(equations []string) bool {
if len(equations) == 0 {
return false
}
uf := UnionFind{}
uf.init(26)
uf := template.UnionFind{}
uf.Init(26)
for _, equ := range equations {
if equ[1] == '=' && equ[2] == '=' {
uf.union(int(equ[0]-'a'), int(equ[3]-'a'))
uf.Union(int(equ[0]-'a'), int(equ[3]-'a'))
}
}
for _, equ := range equations {
if equ[1] == '!' && equ[2] == '=' {
if uf.find(int(equ[0]-'a')) == uf.find(int(equ[3]-'a')) {
if uf.Find(int(equ[0]-'a')) == uf.Find(int(equ[3]-'a')) {
return false
}
}