zoukankan      html  css  js  c++  java
  • 200岛屿数量

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

    来源:https://leetcode-cn.com/problems/number-of-islands/

    法一:bfs 别人的代码

    思路:先用一个bool数组用于记录标记过的每个位置,再依次遍历每个位置,一旦遇到一个1的区域,就把它全部遍历完,并把遍历过的记入bool数组中,本题的关键是一旦遇到一个区域就全部遍历完

    from typing import List
    from collections import deque
    class Solution:
        #        x-1,y
        # x,y-1    x,y      x,y+1
        #        x+1,y
        # 方向数组,它表示了相对于当前位置的 4 个方向的横、纵坐标的偏移量,这是一个常见的技巧
        directions = [(-1, 0), (0, -1), (1, 0), (0, 1)]
        def numIslands(self, grid: List[List[str]]) -> int:
            m = len(grid)
            # 特判
            if m == 0:
                return 0
            n = len(grid[0])
            # 制作标记矩阵,如果遍历过该点了,标记为True,本来为False
            marked = [[False for _ in range(n)] for _ in range(m)]
            count = 0
            # 从第 1 行、第 1 格开始,对每一格尝试进行一次 DFS 操作
            for i in range(m):
                for j in range(n):
                    # 只要是陆地,且没有被访问过的,就可以使用 BFS 发现与之相连的陆地,并进行标记
                    if not marked[i][j] and grid[i][j] == '1':
                        # count 可以理解为连通分量,你可以在广度优先遍历完成以后,再计数,
                        # 即这行代码放在【位置 1】也是可以的
                        count += 1
                        queue = deque()
                        queue.append((i, j))
                        # 注意:这里要标记上已经访问过
                        marked[i][j] = True
                        while queue:
                            cur_x, cur_y = queue.popleft()
                            # 得到 4 个方向的坐标
                            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
                        #【位置 1】
            return count
    View Code

    法二:并查集

    思路:遍历每个位置,如果当前位置为1,则向上和向左遍历两个位置,如果上面的位置为1,则以其为key,以当前位置为values进行记录,这样每个区域都有一个最高级别的values,最后把这个values提取出来,values的不同个数即为区域的个数。

    from typing import List
    class Solution:
        def numIslands(self, grid: List[List[str]]) -> int:
            f = {}
            def find(x):
                f.setdefault(x, x)
                # 如果不相等,则说明之前已经将该位置进行标记为某一类了,
                if f[x] != x:
                    f[x] = find(f[x])
                return f[x]
            # y是当前为1的位置,x是向上或向左为1的位置
            # 注意这个字典中,前面的key包含于后面的values,也就是说values是上级
            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)
    if __name__ == '__main__':
        grid = [['1', '0', '1'],
                ['1', '0', '1'],
                ['0', '1', '1'],]
        solution = Solution()
        result = solution.numIslands(grid)
        print(result)
    View Code

    ttt

  • 相关阅读:
    尚硅谷韩顺平Linux教程学习笔记
    第15章 自动编码器
    问题总结
    日常问题记录
    SQLServer日常bug记录
    .NetCore使用NLog写入数据库总结
    C#操作XML文档
    C#中的 ?/?:/?? 三者的区别及用法
    git 命令从入门到放弃
    通过反射技术获得类中的所有属性
  • 原文地址:https://www.cnblogs.com/xxswkl/p/12291131.html
Copyright © 2011-2022 走看看