leetcode(Union)

leetcode Union 并查集

# leetcode 130 被环绕的区域
# 给定一个二维的矩阵,包含 'X' 和 'O'(字母 O)。找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
# 被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。
# 如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

# 找到被x包围的o不容易找,这时候就反其道而行之,找没有被x包围的o,然后将其先替换成为其他字母,然后最终遍历整个表,将符号变为o,o变为x
# 解题思想:DFS and BFS
"""
x x x x       x x x x       x x x x       x x x x
x x o x ----> x x o x ----> x x o x ----> x x x x
x o x x       x o x x       x # x x       x o x x 
x o x x       x # x x       x # x x       x o x x
"""
# DFS解题
def solve(self, board):
        """
        :type board: List[List[str]]
        :rtype: None Do not return anything, modify board in-place instead.
        """
        # 如果board是空的,则返回
        if not board:
            return 
        # 计算数组的row和col
        row = len(board)
        col = len(board[0])
        # 如果row和col小于3,则不可能出现被包围的o
        if row < 3 or col < 3:
            return board
        # 深度优先遍历,首先,遍历第一行,最后一行,第一列以及最后一列,遇到x pass ,遇到 o 将 o 先写成 # 然后对这个地方朝向上下左右进行深度优先遍历,
        # 出界或者遇到 x 返回,遇到 o 将其改成 # ,然后递归的对这个 o 上下左右进行深度优先遍历,重复上述操作,直到没有复合要求的点
        def dfs(i,j):
            # 如果i和j越界或者是遇见了x则返回
            if i < 0 or j < 0 or i >= row or j >= col or board[i][j] == 'x':
                return 
            # 如果均不越界,以及遇见了‘o’,首先将其变为'#'
            board[i][j] == '#'
            # 然后对其四个方向进行递归操作
            dfs(i-1,j)
            dfs(i+1,j)
            dfs(i,j-1)
            dfs(i,j+1)
        # 对第一列,最后一列进行查询
        for i in range(row):
            dfs(i,0)
            dfs(i,col-1)
        # 对第一行,最后一行进行查询
        for i in range(col):
            dfs(0,i)
            dfs(row-1,i)
        # 全部搜索完毕后,将board中的‘#’ 变为‘o’,o变为x
        for i in range(row):
            for j in range(col):
                if board[i][j] == 'o':
                    board[i][j] == 'x'
                if board[i][j] == '#':
                    board[i][j] == 'o'
        
# BFS解题
# BFS解题的主要思想:利用队列模拟bfs操作,其实主要的思想与上述的DFS类似
def solve(self, board):
        """
        :type board: List[List[str]]
        :rtype: None Do not return anything, modify board in-place instead.
        """
        # 如果board是空的,则返回
        if not board:
            return 
        # 计算board的row和col
        row = len(board)
        col = len(board[0])
        # 如果col和row小于3,则不可能出现被x包围的o
        if col < 3 or row < 3:
            return board
        # 广度优先遍历,
        def bfs(i,j):
            # 首先导入双端队列数据结构,方便与下面的操作
            from collections import deque
            queue = deque()
            # 首先将传入的广度优先遍历的跟节点穿入到双端队列中
            queue.appendleft((i,j))
            while queue:
                i, j = queue.pop()
                # 判断i,j是否越界,或者说是board[i][j]是否为'o'
                if i < 0 or j < 0 or i > row-1 or j > col-1 or board[i][j] == 'x':
                    return 
                # 否则,就修改board[i][j] = '#'
                board[i][j] = '#'
                # 将所有的邻接节点加入到双端队列中
                queue.appendleft((i+1,j))
                queue.appendleft((i-1,j))
                queue.appendleft((i,j+1))   
                queue.appendleft((i,j-1))
        # 遍历第一行与最后一行
        for i in range(col):
            bfs(0,i)
            bfs(row-1,i)
        # 遍历第一列与最后一列
        for i in range(row):
            bfs(i,0)
            bfs(i,col-1)
        # 全部遍历完成之后,再修改其中的内容
        for i in range(row):
            for j in range(col):
                if board[i][j] == 'o':
                    board[i][j] == 'x'
                if board[i][j] == '#':
                    board[i][j] == 'o'
                
                    
        
# Union解题
# Union解题的主要思想:
# 并查集的思想就是,同一个连通区域内的所有点的根节点是同一个。
# 将每个点映射成一个数字。先假设每个点的根节点就是他们自己,然后我们以此输入连通的点对,
# 然后将其中一个点的根节点赋成另一个节点的根节点,这样这两个点所在连通区域又相互连通了。
# 并查集的基本操作
# 1,find(int m):查找m的根节点
par = {}
def find(m):
    """
    :type m : int
    :rtyoe :root
    """
    par.setdefault(x,x)
    if par[x] != x:
        par[x] = find(par[x])
    return par[x]
# 2,isConnected(int m,int n) 判断m,n两个点是否在同一个连通区域
def isConnected(m,n):
    """
    :type m : int
    :type n : int
    :rtype : bool
    """
    return find(m) == find(n)
# 3,union(int m, int n) 合并m,n两个点所在的连通区域
def union(m,n):
    """
    :type m : int
    :type n : int
    :rtype : None
    """
    find(find(n)) = find(m)
    

def solve(self, board):
        """
        :type board: List[List[str]]
        :rtype: None Do not return anything, modify board in-place instead.
        """
        # f词典收录节点与该节点的父节点的映射
        f = {}
        # 并查集的基本操作之一,查找点x的跟节点
        def find(x):
            #  setdefault() 返回的键如果不在字典中,会添加键(更新字典)
            f.setdefault(x, x)
            # 寻找该节点的最终跟节点的操作,也相当于采用了递归的方法,知道找到最终的根节点
            if f[x] != x:
                f[x] = find(f[x])
            # 返回最终的x的根节点
            return f[x]
        # 并查集的基本操作之一,合并m,n两个节点所在的连通区域
        def union(x, y):
            # 合并的思想是,先找的y的跟节点,然后将y的根节点的跟节点映射到x的跟节点上面去
            f[find(y)] = find(x)

            
        # 如果board为空
        if not board or not board[0]:
            return
        # 计算board的row和col
        row = len(board)
        col = len(board[0])
        # dummy代表不需要修改的'o'的根节点
        dummy = row * col
        # 对表中所有的元素进行遍历
        for i in range(row):
            for j in range(col):
                if board[i][j] == "O":
                    # 如果找到了'o',并且其存在于边界上,则
                    if i == 0 or i == row - 1 or j == 0 or j == col - 1:
                        union(i * col + j, dummy)
                    else:
                        for x, y in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
                            if board[i + x][j + y] == "O":
                                union(i * col + j, (i + x) * col + (j + y))
        
        for i in range(row):
            for j in range(col):
                if find(dummy) == find(i * col + j):
                    board[i][j] = "O"
                else:
                    board[i][j] = "X"

# leetcode 200. 岛屿数量
# 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。
# 一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。
class Solution(object):
    
    # 并查集解题:
    def numIslands(self, grid):
        """
        :type grid: List[List[str]]
        :rtype: int
        """
        f = {}

        def find(x):
            f.setdefault(x, x)
            if f[x] != x:
                f[x] = find(f[x])
            return f[x]

        def union(x, y):
            f[find(x)] = find(y)

        if not grid: return 0
        row = len(grid)
        col = len(grid[0])

        for i in range(row):
            for j in range(col):
                if grid[i][j] == "1":
                    for x, y in [[-1, 0], [0, -1]]:
                        tmp_i = i + x
                        tmp_j = j + y
                        if 0 <= tmp_i < row and 0 <= tmp_j < col and grid[tmp_i][tmp_j] == "1":
                            union(tmp_i * col + tmp_j, i * col + j)
        # print(f)
        res = set()
        for i in range(row):
            for j in range(col):
                if grid[i][j] == "1":
                    res.add(find((i * col + j)))
        return len(res)
    
    # DFS
    def numIslands(self, grid):
        """
        :type grid: List[List[str]]
        :rtype: int
        """
        if not grid: return 0
        row = len(grid)
        col = len(grid[0])
        cnt = 0

        def dfs(i, j):
            grid[i][j] = "0"
            for x, y in [[-1, 0], [1, 0], [0, -1], [0, 1]]:
                tmp_i = i + x
                tmp_j = j + y
                if 0 <= tmp_i < row and 0 <= tmp_j < col and grid[tmp_i][tmp_j] == "1":
                    dfs(tmp_i, tmp_j)

        for i in range(row):
            for j in range(col):
                if grid[i][j] == "1":
                    dfs(i, j)
                    cnt += 1
        return cnt
    
    # BFS
    def numIslands(self, grid):
        """
        :type grid: List[List[str]]
        :rtype: int
        """
        from collections import deque
        if not grid: return 0
        row = len(grid)
        col = len(grid[0])
        cnt = 0

        def bfs(i, j):
            queue = deque()
            queue.appendleft((i, j))
            grid[i][j] = "0"
            while queue:
                i, j = queue.pop()
                for x, y in [[-1, 0], [1, 0], [0, -1], [0, 1]]:
                    tmp_i = i + x
                    tmp_j = j + y
                    if 0 <= tmp_i < row and 0 <= tmp_j < col and grid[tmp_i][tmp_j] == "1":
                        grid[tmp_i][tmp_j] = "0"
                        queue.appendleft((tmp_i, tmp_j))

        for i in range(row):
            for j in range(col):
                if grid[i][j] == "1":
                    bfs(i, j)
                    cnt += 1
        return cnt
        
# leetcode 547. 朋友圈
# 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。
class Solution(object):
    def findCircleNum(self, M):
        """
        :type M: List[List[int]]
        :rtype: int
        """
        parent = [-1 for _ in range(len(M))]

        def find(parent, i):
            if parent[i] == -1: return i
            return find(parent, parent[i])
        
        def union(parent, x, y):
            xroot = find(parent, x)
            yroot = find(parent, y)
            if xroot != yroot:
                parent[xroot] = yroot
        
        def union_find(Matrix):
            for i in range(len(Matrix)):
                for j in range(len(Matrix)):
                    if Matrix[i][j] == 1 and i != j:
                        union(parent, i, j)
            count = 0
            for i in range(len(parent)):
                if parent[i] == -1:
                    count += 1
            return count
        
        return union_find(M)
# leetcode 1319  连通网络的操作次数
"""
算法框架如下:

比较 n - 1 和 len(connections):

如果前者大于后者,那么一定无解,返回 -1;

如果前者小于等于后者,那么我们统计出图中的连通分量数 k,返回 k - 1。

统计图中连通分量数的方法有很多,我们介绍深度优先搜索和并查集两种方法。

"""

class Solution(object):
    # DFS
    def makeConnected(self, n, connections):
        """
        :type n: int
        :type connections: List[List[int]]
        :rtype: int
        """
        if len(connections) < n - 1:
            return -1
        
        edges = {x: list() for x in range(n)}
        for c0, c1 in connections:
            edges[c0].append(c1)
            edges[c1].append(c0)
        used = set()

        def dfs(u):
            used.add(u)
            for v in edges[u]:
                if v not in used:
                    dfs(v)
        
        part = 0
        for i in range(n):
            if i not in used:
                part += 1
                dfs(i)
        
        return part - 1
    # 并查集
    def makeConnected(self, n, connections):
        """
        :type n: int
        :type connections: List[List[int]]
        :rtype: int
        """
        if len(connections) < n - 1:
            return -1
        
        fa = [x for x in range(n)]

        def findset(x):
            if x != fa[x]:
                fa[x] = findset(fa[x])
            return fa[x]
        
        part = n
        for c0, c1 in connections:
            p, q = findset(c0), findset(c1)
            if p != q:
                part -= 1
                fa[p] = q
        
        return part - 1





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值