蓝桥杯备赛(一)—— 并查集模板

第一次参加蓝桥杯,也是最后一次了。我是个小白,准备几个模板到时候坐牢也不会那么难受吧。

1、并查集的用途

  • 查询元素a和元素b是否属于同一组
  • 合并元素a和元素b所在的组

2、并查集的结构

  • 每个元素对应一个节点,每个组对应一棵树。
  • 在并査集中,哪个节点是哪个节点的父亲以及树的形状等信息无需多加关注,整体组成一个树形结构才是重要的。

(1) 初始化

准备n节点来表示n个元素。最开始时没有边。

(2) 合并

从一个组的根向另一个组的根连边,这样两棵树就变成了一棵树,也就把两个组合并为一个组了。

(3) 查询

为了査询两个节点是否属于同一组,我们需要沿着树向上走 ,来査询包含这个元素的树的根是谁。.

如果两个节点走到了同一个根,那么就可以知道它们属于同一组。

3、并查集实现中的注意点

  • 对于每棵树,记录这棵树的高度(rank)。
  • 合并时如果两棵树的rank不同,那么从rank小的向rank大的连边。
  • 此外,通过路径压缩,可以使得并査集更加高效。对于每个节点,一旦向上走到了一次根节点,就把这个点到父亲的边改为直接连向根。在此之上,不仅仅是所查询的节点,在查询过程中向上经过的所有的节点,都改为直接连到根上。这样再次查询这些节点时,就可以很快知道根是谁了。

4、并查集的复杂度

O ( α ( n ) ) O(\alpha(n)) O(α(n))

5、并查集的实现

class unionFindSet(object):
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n
    
    def find(self, x):
        if self.parent[x] == x:
            return x
        self.parent[x] = self.find(self.parent[x])
        return self.parent[x]
    
    def unite(self, x, y):
        x, y = self.find(x), self.find(y)
        if x == y:
            return 
        if self.rank[x] < self.rank[y]:
            self.parent[x] = y
        else:
            self.parent[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1

    def same(self, x, y):
        return self.find(x) == self.find(y)

LeetCode并查集题

1584.连接所有点的最小费用

# 把上面那段复制下来

class Solution(object):
    def minCostConnectPoints(self, points):
        distince = lambda x, y : abs(points[x][0] - points[y][0]) + abs(points[x][1] - points[y][1])
        edges = []
        n = len(points)
        for i in range(n - 1):
            for j in range(i + 1, n):
                edges.append((i, j, distince(i, j)))
        edges.sort(key = lambda x : x[2])
        num = 1
        ans = 0
        ufs = unionFindSet(n)
        for x, y, length in edges:
            if not ufs.same(x, y):
                num += 1
                ans += length
                ufs.unite(x, y)
                if num == n:
                    break
        return ans
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值