leetcode 765 并查集+座位问题

这是一个经典的换座位问题,可以很好地利用并查集解决。如果有N对情侣彼此纠缠,那么共需要交换N-1次。知道这个定律后,咱们只需用并查集统计出有几个团即可。注:并查集的按秩合并和路径压缩是很好地技巧,咱们再在并查集内部加一个父亲节点统计儿子数量的字典即可。

from collections import defaultdict
class Solution:
    def minSwapsCouples(self, row: List[int]) -> int:
        class Unionfind:
            def __init__(self, n):
                self.father = [-1 for _ in range(n)]
                self.rank = [0 for _ in range(n)]
                self.father2childnum = defaultdict(int)

            def union(self, a, b):
                r1, r2 = self.find(a), self.find(b)
                if r1 == r2: return
                if self.rank[r1] <= self.rank[r2]:
                    self.rank[r1] = max(self.rank[r2]+1, self.rank[r1])
                    self.father[r1] = r2
                    self.father2childnum[r2] += self.father2childnum[r1]+1
                    del self.father2childnum[r1]
                else:
                    self.rank[r2] = max(self.rank[r1]+1, self.rank[r2])
                    self.father[r2] = r1
                    self.father2childnum[r1] += self.father2childnum[r2]+1
                    del self.father2childnum[r2]

            def find(self, a):
                l = []
                while self.father[a] >= 0:
                    l.append(a)
                    a = self.father[a]
                
                for num in l:
                    self.father[num] = a

                return a

        u = Unionfind(len(row))

        for i in range(len(row)):
            if row[i] & 1:
                row[i] -= 1

        for i in range(0, len(row), 2):
            u.union(row[i], row[i+1])

        ret = 0
        for father in u.father2childnum:
            ret += u.father2childnum[father]

        return ret

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值