14 并查集

  • 基本概念
    • 并查集是一种树型的数据结构,用于处理一些不交集的合并及查询问题
    • 示意图
  • 常用方法
    • Find:确定元素属于哪一个子集。可以用来确定两个元素是否属于同一子集
    • Union: 将两个子集合并成同一个集合
    • 示意图
  • 代码实现(伪代码)

function MakeSet(x)

    x.parent := x

    

function Find(x)

    if x.parent == x

        return x

    else

        return Find(x.parent)

        

function Union(x, y)

    xRoot := Find(x)

    yRoot := Find(y)

    xRoot.parent := yRoot

  

  • 优化
    • rank
      • 示意图
      • 伪代码

function MakeSet(x)

    x.parent := x

    x.rank := 0

        

function Union(x, y)

    xRoot := Find(x)

    yRoot := Find(y)

    if xRoot == yRoot

        return

        

    if xRoot.rank < yRoot.rank

        xRoot.parent := yRoot

    else if xRoot.rank > yRoot.rank

        yRoot.parent := xRoot

    else

        yRoot.parent := xRoot

        xRoot.rank := xRoot.rank + 1

   

  • 路径压缩
    • 示意图
    • 伪代码

function MakeSet(x)

    x.parent := x

    

function Find(x)

    root = x

    while root != root.parent

        root := root.parent

    

    while x != x.parent

        tmp = x.parent

        x.parent = root

        x = tmp

        

    return root

   

  • Python 实现 -- 包含两种优化

class UnionUF(object):

    def __init__(self, n):

        self.parent = [-1] * n

        self.rank = [0] * n

        for i in range(n):

            self.parent[i] = i

   

    def find(self, i):

        root = i

        while root != self.parent[root]:

            root = self.parent[root]

   

        # 路径压缩

        while i != self.parent[i]:

            i, self.parent[i] = self.parent[i], root

   

        return root

   

    def union(self, x, y):

        rootx = self.find(x)

        rooty = self.find(y)

        if rootx == rooty:

            return 0# 两者属于同一集合,没有发生合并操作

        if self.rank[rootx] > self.rank[rooty]:

            self.parent[rooty] = rootx

        elif self.rank[rootx] < self.rank[rooty]:

            self.parent[rootx] = rooty

        else:

            self.parent[rootx] = rooty

            self.rank[rooty] += 1

        return 1# 发生合并操作 

class UnionUF(object):

    def __init__(self, n):

        self.parent = [-1] * n

        self.rank = [0] * n

        for i in range(n):

            self.parent[i] = i

   

    def find(self, i):

        root = i

        while root != self.parent[root]:

            root = self.parent[root]

   

        # 路径压缩

        while i != self.parent[i]:

            i, self.parent[i] = self.parent[i], root

   

        return root

   

    def union(self, x, y):

        rootx = self.find(x)

        rooty = self.find(y)

        if rootx == rooty:

            return 0# 两者属于同一集合,没有发生合并操作

        if self.rank[rootx] > self.rank[rooty]:

            self.parent[rooty] = rootx

        elif self.rank[rootx] < self.rank[rooty]:

            self.parent[rootx] = rooty

        else:

            self.parent[rootx] = rooty

            self.rank[rooty] += 1

        return 1# 发生合并操作

            

            

class Solution:

    def numIslands(self, grid: List[List[str]]) -> int:

        if not grid:

            return 0

        m, n = len(grid), len(grid[0])

        union = UnionUF(m*n)

        res = 0

        dx, dy = [-1, 1, 0, 0], [0, 0, -1, 1]

        

        for i in range(m):

            for j in range(n):

                if grid[i][j] == "1":

                    res += 1

                    for count in range(len(dx)):

                        ni, nj = i + dx[count], j + dy[count]

                        if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == "1":

                            res -= union.union(i*n + j, ni*n + nj)

        return res

   

class UnionUF(object):

    def __init__(self, n):

        self.parent = [-1] * n

        self.rank = [0] * n

        for i in range(n):

            self.parent[i] = i

   

    def find(self, i):

        root = i

        while root != self.parent[root]:

            root = self.parent[root]

   

        # 路径压缩

        while i != self.parent[i]:

            i, self.parent[i] = self.parent[i], root

   

        return root

   

    def union(self, x, y):

        rootx = self.find(x)

        rooty = self.find(y)

        if rootx == rooty:

            return 0# 两者属于同一集合,没有发生合并操作

        if self.rank[rootx] > self.rank[rooty]:

            self.parent[rooty] = rootx

        elif self.rank[rootx] < self.rank[rooty]:

            self.parent[rootx] = rooty

        else:

            self.parent[rootx] = rooty

            self.rank[rooty] += 1

        return 1# 发生合并操作

   

   

class Solution:

    def findCircleNum(self, M: List[List[int]]) -> int:

        if not M:

            return 0

        m = len(M)

        union = UnionUF(m)

        res = 0

   

        for i in range(m):

            res += 1

            for count in range(m):

                if i == count:

                    continue

                if M[i][count] == 1:

                    res -= union.union(i, count)

        return res

   

posted @ 2019-06-07 21:23  木子识时务  阅读(148)  评论(0编辑  收藏  举报