[Leetcode] [Tutorial] 图论


200. 岛屿数量

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

示例 1:
输入:grid = [
[“1”,“1”,“1”,“1”,“0”],
[“1”,“1”,“0”,“1”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“0”,“0”,“0”]
]
输出:1

示例 2:
输入:grid = [
[“1”,“1”,“0”,“0”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“1”,“0”,“0”],
[“0”,“0”,“0”,“1”,“1”]
]
输出:3

Solution

一般来说,一个合理的方法是遍历整个二维网格,每当我们遇到一个1时,我们就对它进行深度优先搜索或者广度优先搜索,并将搜索到的所有相邻的1标记为已访问。然后我们继续遍历网格的其余部分,每当我们遇到新的未访问的1时,我们就知道我们找到了一个新的岛屿。

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        m, n = len(grid), len(grid[0])
        count = 0

        def dfs(x, y):
            # 如果坐标超出边界或者该位置不是陆地(已经被访问过或者本来就是水),则结束当前递归
            if x < 0 or x >= m or y < 0 or y >= n or grid[x][y] == '0':
                return
            grid[x][y] = '0'
            dfs(x - 1, y)
            dfs(x + 1, y)
            dfs(x, y - 1)
            dfs(x, y + 1)

        # 遍历所有单元格,当发现陆地时,进行深度优先搜索,并将岛屿数量加1
        for i in range(m):
            for j in range(n):
                if grid[i][j] == '1':
                    count += 1
                    dfs(i, j)
        return count

也可以直接在主函数中实现深度优先搜索。

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        # 定义上下左右四个方向
        directions = [(0, 1), (0, -1), (-1, 0), (1, 0)]

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

        # 遍历所有单元格,当发现陆地时,进行深度优先搜索,并将岛屿数量加1
        for i in range(m):
            for j in range(n):
                if grid[i][j] == '1':
                    # 将访问过的陆地变为水
                    grid[i][j] = '0'
                    count += 1
                    # 使用栈进行深度优先搜索
                    stack = [(i, j)]
                    while stack:
                        cur_i, cur_j = stack.pop()
                        for di, dj in directions:
                            ni, nj = cur_i + di, cur_j + dj
                            if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == '1':
                                # 将访问过的陆地变为水
                                grid[ni][nj] = '0'
                                stack.append((ni, nj))
        return count

广度优先搜索也是一个可行的解决方案。

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        # 定义上下左右四个方向
        directions = [(0, 1), (0, -1), (-1, 0), (1, 0)]

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

        def bfs(i, j):
            # 使用队列进行广度优先搜索
            queue = deque([(i, j)])
            while queue:
                i, j = queue.popleft()
                for di, dj in directions:
                    ni, nj = i + di, j + dj
                    if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == '1':
                        # 将访问过的陆地变为水
                        grid[ni][nj] = '0'
                        queue.append((ni, nj))

        # 遍历所有单元格,当发现陆地时,进行广度优先搜索,并将岛屿数量加1
        for i in range(m):
            for j in range(n):
                if grid[i][j] == '1':
                    # 将访问过的陆地变为水
                    grid[i][j] = '0'
                    bfs(i, j)
                    count += 1

        return count

994. 腐烂的橘子

在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:

值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。

返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1 。

示例 1:

输入:grid = [[2,1,1],[1,1,0],[0,1,1]]
输出:4

Solution

这个问题实际上是一个典型的广度优先搜索问题,因为我们想知道腐烂的橘子需要多长时间才能让所有的新鲜橘子都腐烂。我们可以从所有的腐烂的橘子开始,将他们的相邻的新鲜橘子都腐烂,并将腐烂的时间加一,直到没有新的橘子腐烂。如果结束时仍然有新鲜的橘子,那么就返回 -1,否则返回 最大的腐烂时间 - 1。

class Solution:
    def orangesRotting(self, grid: List[List[int]]) -> int:
        # 定义上下左右四个方向
        directions = [(0, 1), (0, -1), (-1, 0), (1, 0)]

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

        queue = deque()
        fresh = 0

        # 将所有腐烂的橘子加入队列,并计算新鲜橘子的数量
        for i in range(m):
            for j in range(n):
                if grid[i][j] == 2:
                    queue.append((i, j, 0))  # i, j 为坐标,0 为腐烂时间
                elif grid[i][j] == 1:
                    fresh += 1

        if fresh == 0:  # 如果没有新鲜橘子,直接返回0
            return 0

        while queue:
            i, j, t = queue.popleft()
            for di, dj in directions:
                ni, nj = i + di, j + dj
                if 0 <= ni < m and 0 <= nj < n and grid[ni][nj] == 1:
                    grid[ni][nj] = 2
                    fresh -= 1
                    queue.append((ni, nj, t + 1))

        # 如果仍然有新鲜橘子,返回-1
        if fresh > 0:
            return -1

        # 否则,返回最后一个腐烂的橘子的时间
        return t

猜你喜欢

转载自blog.csdn.net/weixin_45427144/article/details/131641764