200. 岛屿数量 BFS+DFS+并查集(Python 3)

给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

示例 1:

输入:
11110
11010
11000
00000

输出: 1

示例 2:

输入:
11000
11000
00100
00011

输出: 3

本题根本是求连通域个数

  • 循环实现广度优先BFS(使用队列):
from collections import deque

class Solution:
    directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
    
    def numIslands(self, grid: List[List[str]]) -> int:
        m = len(grid) #行
        if m == 0:
            return 0
        n = len(grid[0]) # 列
        marked = [[False for i in range(n)] for i in range(m)]
        count = 0
        
        for i in range(m):
            for j in range(n):
                if not marked[i][j] and grid[i][j] == '1':
                    queue = deque()
                    count += 1
                    queue.append((i,j))
                    marked[i][j] = True
                    while queue:
                        cur_x, cur_y = queue.popleft() # key step
                        for direction in self.directions:
                            new_i = cur_x + direction[0]
                            new_j = cur_y + direction[1]
                            if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][new_j] == '1':
                                queue.append((new_i, new_j))
                                marked[new_i][new_j] = True
        return count
  • 循环实现深度优先DFS(使用栈):
class Solution:
    directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]

    def numIslands(self, grid: List[List[str]]) -> int:
        count = 0
        m = len(grid)
        if m == 0:
            return 0
        n = len(grid[0])
        marked = [[False for i in range(n)] for i in range(m)]
        for i in range(m):
            for j in range(n):
                if not marked[i][j] and grid[i][j] == '1':
                    stack = []
                    stack.append((i, j))
                    marked[i][j] = True
                    count += 1
                    while stack:
                        cur_i, cur_j = stack.pop()
                        for direction in self.directions:
                            new_i = cur_i + direction[0]
                            new_j = cur_j + direction[1]
                            if 0 <= new_i < m and 0 <= new_j < n and not marked[new_i][new_j] and grid[new_i][new_j] == '1':
                                stack.append((new_i, new_j))
                                marked[new_i][new_j] = True
        return count
  • 递归实现DFS方法:
class Solution:
    directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]

    def find(self, grid: List[List[str]], i, j):
        if i < 0 or i >= len(grid) or j < 0 or j >= len(grid[0]) or grid[i][j] != '1':
            return
        grid[i][j] = '2'
        for direction in self.directions:
            self.find(grid, i + direction[0], j + direction[1])
    
    def numIslands(self, grid: List[List[str]]) -> int:
        count = 0
        m = len(grid)
        if m == 0:
            return 0
        n = len(grid[0])
        for i in range(m):
            for j in range(n):
                if grid[i][j] == '1':
                    self.find(grid, i, j)
                    count += 1
        return count
  • 并查集,只考虑向右和向下两个方向,而不是四个方向
from typing import List
class Solution:
    # 并查集
    
    def numIslands(self, grid: List[List[str]]) -> int:
        # 每个节点表示集合的一个元素,每个元素用一个数字表示
        class UnionFind:
            def __init__(self, n: int):
                self.count = n
                self.parent = [i for i in range(n)] # 每个元素的树根,开始时为自身
                self.rank = [1 for _ in range(n)] # 每个节点的初始秩
            
            def getCount(self) -> int:
                return self.count
            
            def find(self,p): # 递归寻找树根
                if(p != self.parent[p]):
                    self.parent[p] = self.find(self.parent[p])
                return self.parent[p]
            
            def union(self, p, q): # 按秩合并,将具有较小秩的树根指向具有较大秩的树根
                p_root = self.find(p)
                q_root = self.find(q)
                if p_root == q_root:
                    return
                if self.rank[p_root] > self.rank[q_root]:
                    self.parent[q_root] = p_root
                    self.rank[p_root] += 1
                else:
                    self.parent[p_root] = q_root
                    self.rank[q_root] += 1
                self.count -= 1
        
        m = len(grid)
        if m == 0:
            return 0
        n = len(grid[0])

        def getIndex(x, y):
            return x * n + y

        uf = UnionFind(m * n)
        water = 0

        for i in range(m):
            for j in range(n):
                if grid[i][j] == '0':
                    water += 1
                else:
                    if i + 1 < m and grid[i + 1][j] == '1':
                        uf.union(getIndex(i, j), getIndex(i + 1, j))
                    if j + 1 < n and grid[i][j + 1] == '1':
                        uf.union(getIndex(i, j), getIndex(i, j + 1))

        return uf.getCount() - water
posted @ 2020-03-29 19:25  libbin  阅读(603)  评论(0编辑  收藏  举报