并查集

1、定义

  • 并查集是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。常常在使用中以森林来表示。
  • 并查集的思想是通过标记确定该顶点所在的组
  • 1、应用:判断一个图中两个点是否联通;分组问题
  • 2、函数:初始化(init)、合并(Union)、查询(Find)
  • 3、初始化(init): 初始化一个N大小的数组,初始值为下标
  • 4、合并(Union):把两个不相交的集合合并为一个集合。
  • 5、查询(Find):查询两个元素是否在同一个集合中。使用递归实现,访问父节点,直至根节点。要判断两个元素是否属于同一个集合,只需要看它们的根节点是否相同即可。

复杂度

2、实现

// 隔代路径压缩
func find(x int) int {
    for x != fa[x] {
        fa[x] = fa[fa[x]]
        x = fa[x]
    }
    return x
}
// 彻底路径压缩
func find(x int) int {
    if fa[x] != x {
        fa[x] = find(fa[x])
    }
    return fa[x]
}

不带秩

package main

import "fmt"

func main() {
    fa = Init(10)
    union(3, 1)
    union(1, 4)
    fmt.Println(find(3))
    fmt.Println(query(3, 4))
    fmt.Println(query(3, 5))
    fmt.Println(fa)
}

var fa []int

// Init 初始化
func Init(n int) []int {
    arr := make([]int, n)
    for i := 0; i < n; i++ {
        arr[i] = i
    }
    return arr
}

// 查询
func find(x int) int {
    if fa[x] != x {
        fa[x] = find(fa[x])
    }
    return fa[x]
}

// 合并
func union(i, j int) {
    fa[find(i)] = find(j)
}

func query(i, j int) bool {
    return find(i) == find(j)
}

带秩

package main

import "fmt"

func main() {
    fa, rank = Init(10)
    union(3, 1)
    union(1, 4)
    fmt.Println(find(3))
    fmt.Println(query(3, 4))
    fmt.Println(query(3, 5))
    fmt.Println(fa, rank)
}

var fa []int
var rank []int

// Init 初始化
func Init(n int) ([]int, []int) {
    arr := make([]int, n)
    r := make([]int, n)
    for i := 0; i < n; i++ {
        arr[i] = i
        r[i] = 1
    }
    return arr, r
}

// 查询
func find(x int) int {
    if fa[x] == x {
        return x
    }
    // 路径压缩
    fa[x] = find(fa[x])
    return fa[x]
}

// 合并
func union(i, j int) {
    // 按秩合并
    x, y := find(i), find(j)
    if rank[x] <= rank[y] {
        fa[x] = y
    } else {
        fa[y] = x
    }
    if rank[x] == rank[y] && x != y {
        rank[y]++ // 如果深度相同且根节点不同,则新的根节点的深度+1
    }
}

func query(i, j int) bool {
    return find(i) == find(j)
}

map系列

package main

import (
    "fmt"
    "math"
)

func main() {
    fa = Init([]int{1, 3, 4, 6, 7, 8, 9, 10})
    fmt.Println(fa)
    union(3, 1)
    union(1, 4)
    fmt.Println(find(3))
    fmt.Println(query(3, 4))
    fmt.Println(query(3, 5))
}

var fa map[int]int

// Init 初始化
func Init(data []int) map[int]int {
    n := len(data)
    arr := make(map[int]int)
    for i := 0; i < n; i++ {
        arr[data[i]] = data[i]
    }
    return arr
}

// 查询
func find(x int) int {
    if _, ok := fa[x]; !ok {
        return math.MinInt32 // 特殊处理
    }
    res := x
    for res != fa[res] {
        res = fa[res]
    }
    return res
}

// 合并
func union(i, j int) {
    x, y := find(i), find(j)
    if x == y {
        return
    } else if x == math.MinInt32 || y == math.MinInt32 {
        return
    }
    fa[x] = y
}

func query(i, j int) bool {
    return find(i) == find(j)
}

带count

package main

import "fmt"

func main() {
    fa = Init(10)
    for i := 0; i < 10; i++ {
        if i%2 == 1 {
            count++
        }
    }
    union(3, 1)
    union(1, 4)
    fmt.Println(find(3))
    fmt.Println(query(3, 4))
    fmt.Println(query(3, 5))
    fmt.Println(fa)
}

var fa []int
var count int

// Init 初始化
func Init(n int) []int {
    arr := make([]int, n)
    for i := 0; i < n; i++ {
        arr[i] = i
    }
    count = n
    return arr
}

// 查询
func find(x int) int {
    if fa[x] == x {
        return x
    }
    // 路径压缩
    fa[x] = find(fa[x])
    return fa[x]
}

// 合并
func union(i, j int) {
    x, y := find(i), find(j)
    if x != y {
        fa[x] = y
        count--
    }
}

func query(i, j int) bool {
    return find(i) == find(j)
}

func getCount() int {
    return count
}

传参数

package main

import "fmt"

func main() {
    n := 200
    fa := make([]int, n)
    for i := 0; i < n; i++ {
        fa[i] = i
    }
    union(fa, 10, 20)
    union(fa, 10, 30)
    fmt.Println(find(fa, 20), find(fa, 30))
}

func union(fa []int, a, b int) {
    fa[find(fa, a)] = find(fa, b)
}

func find(fa []int, a int) int {
    for fa[a] != a {
        fa[a] = fa[fa[a]]
        a = fa[a]
    }
    return a
}

struct

package main

import "fmt"

func main() {
    a := &UnionFind{}
    a.Init(10)
    fmt.Println(a.count)
    fmt.Println(a.fa)
}

type UnionFind struct {
    fa    []int
    count int
}

// Init 初始化
func (u *UnionFind) Init(n int) {
    arr := make([]int, n)
    for i := 0; i < n; i++ {
        arr[i] = i
    }
    u.count = n
    u.fa = arr
}

// 查询
func (u UnionFind) find(x int) int {
    if u.fa[x] == x {
        return x
    }
    // 路径压缩
    u.fa[x] = u.find(u.fa[x])
    return u.fa[x]
}

// 合并
func (u *UnionFind) union(i, j int) {
    x, y := u.find(i), u.find(j)
    if x != y {
        u.fa[x] = y
        u.count--
    }
}

func (u UnionFind) query(i, j int) bool {
    return u.find(i) == u.find(j)
}

3、Leetcode

并查集不带权

Title Tag 难度 完成情况
128.最长连续序列 并查集、数组 Hard 完成
130.被围绕的区域 深度优先搜索、广度优先搜索、并查集 Medium 完成
200.岛屿数量 深度优先搜索、广度优先搜索、并查集 Medium 完成
419.甲板上的战舰 Medium 完成
547.朋友圈 深度优先搜索、并查集 Medium 完成
684.冗余连接 树、并查集、图 Medium 完成
765.情侣牵手 贪心算法、并查集、图 Hard 完成
778.水位上升的泳池中游泳 深度优先搜索、广度优先搜索、并查集、
数组、二分查找、矩阵、堆(优先队列)
Hard 完成
785.判断二分图 深度优先搜索、广度优先搜索、
并查集、图
Medium 完成
803
839.相似字符串组 深度优先搜索、广度优先搜索、
并查集、字符串
Hard 完成
886.可能的二分法 深度优先搜索、广度优先搜索、
并查集、图
Medium 完成
947.移除最多的同行或同列石头 深度优先搜索、并查集 Medium 完成
959.由斜杠划分区域 深度优先搜索、广度优先搜索、并查集、图 Medium 完成
990.等式方程的可满足性 并查集、图 Medium 完成
1202.交换字符串中的元素 并查集、数组 Medium 完成
1319.连通网络的操作次数 深度优先搜索、
广度优先搜索、并查集
Medium 完成
1391.检查网格中是否存在有效路径 深度优先搜索、广度优先搜索、并查集、
数组、矩阵
Medium 完成
1568.使陆地分离的最少天数 贪心算法 Medium 完成
1579.保证图可完全遍历 并查集、图 Hard 完成
1584.连接所有点的最小费用 并查集、数组、最小生成树 Medium 完成
1631.最小体力消耗路径 深度优先搜索、广度优先搜索、并查集、
数组、二分查找、矩阵、堆(优先队列)
Medium 完成
1722.执行交换操作后的最小汉明距离 贪心算法、深度优先搜索、并查集 Medium 完成
2076.处理含限制条件的好友请求 并查集、图 Hard 完成
2316.统计无向图中无法互相到达点对数 深度优先搜索、广度优先搜索、并查集、图 Medium 完成

并查集带权

Title Tag 难度 完成情况
399.除法求值 并查集、图 Medium 完成
685
721.账户合并 深度优先搜索、并查集 Medium 完成
985
面试题17.07.婴儿名字 深度优先搜索、广度优先搜索、并茶查集 Medium 完成
Copyright © Zhi2014 2023 all right reserved,powered by Gitbook该文件修订时间: 2023-10-23 15:20:51

results matching ""

    No results matching ""