主题空间

标签: 深度优先搜索 广度优先搜索 并查集 数组 矩阵

难度: Medium

「以扣会友」线下活动所在场地由若干主题空间与走廊组成,场地的地图记作由一维字符串型数组 `grid`,字符串中仅包含 `"0"~"5"` 这 6 个字符。地图上每一个字符代表面积为 1 的区域,其中 `"0"` 表示走廊,其他字符表示主题空间。相同且连续(连续指上、下、左、右四个方向连接)的字符组成同一个主题空间。 假如整个 `grid` 区域的外侧均为走廊。请问,不与走廊直接相邻的主题空间的最大面积是多少?如果不存在这样的空间请返回 `0`。 **示例 1:** >输入:`grid = ["110","231","221"]` > >输出:`1` > >解释:4 个主题空间中,只有 1 个不与走廊相邻,面积为 1。 >![image.png](https://pic.leetcode-cn.com/1613708145-rscctN-image.png) **示例 2:** >输入:`grid = ["11111100000","21243101111","21224101221","11111101111"]` > >输出:`3` > >解释:8 个主题空间中,有 5 个不与走廊相邻,面积分别为 3、1、1、1、2,最大面积为 3。 >![image.png](https://pic.leetcode-cn.com/1613707985-KJyiXJ-image.png) **提示:** - `1 <= grid.length <= 500` - `1 <= grid[i].length <= 500` - `grid[i][j]` 仅可能是 `"0"~"5"`

Submission

运行时间: 1051 ms

内存: 25.8 MB

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

        info = [[0] * n for i in range(m)]

        opts = []
        tmp_opts = None

        for j in range(n):
            opts.append((0, j))
            info[0][j] = 1
            opts.append((m - 1, j))
            info[m - 1][j] = 1
        
        for i in range(1, m - 1):
            opts.append((i, 0))
            info[i][0] = 1
            opts.append((i, n - 1))
            info[i][n - 1] = 1
            for j in range(1, n - 1):
                if grid[i][j] == '0':
                    opts.append((i, j))
                    info[i][j] = 1
        # print(opts)
        while opts:
            tmp_opts = []
            for x, y in opts:
                r, c = x - 1, y
                if r >= 0 and (grid[x][y] == '0' or grid[r][c] == grid[x][y]) and info[r][c] == 0:
                    tmp_opts.append((r, c))
                    info[r][c] = 1
                
                r, c = x + 1, y
                # if r == 1 and c == 1:
                #     print(x, y, grid[x][y], grid[x][y] == 0, grid[x][y] == '0')
                if r < m and (grid[x][y] == '0' or grid[r][c] == grid[x][y]) and info[r][c] == 0:
                    tmp_opts.append((r, c))
                    info[r][c] = 1

                r, c = x, y - 1
                if c >= 0 and (grid[x][y] == '0' or grid[r][c] == grid[x][y]) and info[r][c] == 0:
                    tmp_opts.append((r, c))
                    info[r][c] = 1
                
                r, c = x, y + 1
                if c < n and (grid[x][y] == '0' or grid[r][c] == grid[x][y]) and info[r][c] == 0:
                    tmp_opts.append((r, c))
                    info[r][c] = 1
            opts = tmp_opts
            # print(opts)
        
        # print(info)
        res = 0
        for i in range(1, m - 1):
            for j in range(1, n - 1):
                if info[i][j] > 0:
                    continue
                
                tmp = 1
                opts = [(i, j)]
                info[i][j] = 1
                while opts:
                    tmp_opts = []
                    for x, y in opts:
                        r, c = x - 1, y
                        if grid[r][c] == grid[x][y] and info[r][c] == 0:
                            tmp_opts.append((r, c))
                            info[r][c] = 1
                            tmp += 1

                        r, c = x + 1, y
                        if grid[r][c] == grid[x][y] and info[r][c] == 0:
                            tmp_opts.append((r, c))
                            info[r][c] = 1
                            tmp += 1
                            
                        r, c = x, y - 1
                        if grid[r][c] == grid[x][y] and info[r][c] == 0:
                            tmp_opts.append((r, c))
                            info[r][c] = 1
                            tmp += 1

                        r, c = x, y + 1
                        if grid[r][c] == grid[x][y] and info[r][c] == 0:
                            tmp_opts.append((r, c))
                            info[r][c] = 1
                            tmp += 1
                    opts = tmp_opts
                res = max(res, tmp)
        
        return res



Explain

此题解采用了广度优先搜索(BFS)的方法来解决问题。首先,使用一个二维数组info来记录是否访问过每个单元格。初始时,将所有边界单元格以及所有的'0'(走廊)加入到搜索队列opts中,因为它们都与边界接壳。接下来,进行广度优先搜索,将与走廊相连的主题空间的每个部分标记为已访问。这一步确保了所有与走廊相连的区域都被标记。之后,再遍历数组,对于每一个未被访问的非走廊格子,从该位置出发进行广度优先搜索计算该区域的大小,并更新最大面积。最终返回最大的非与走廊相邻的主题空间面积。

时间复杂度: O(m*n)

空间复杂度: O(m*n)

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

        # 创建一个与grid大小相同的标记数组,记录是否访问过
        info = [[0] * n for i in range(m)]

        opts = []  # 队列,用于BFS
        tmp_opts = None

        # 初始化队列,包括所有边界单元格和'0'单元格
        for j in range(n):
            opts.append((0, j))
            info[0][j] = 1
            opts.append((m - 1, j))
            info[m - 1][j] = 1
        
        for i in range(1, m - 1):
            opts.append((i, 0))
            info[i][0] = 1
            opts.append((i, n - 1))
            info[i][n - 1] = 1
            for j in range(1, n - 1):
                if grid[i][j] == '0':
                    opts.append((i, j))
                    info[i][j] = 1
        # 执行BFS以标记所有与走廊相邻的区域
        while opts:
            tmp_opts = []
            for x, y in opts:
                # 检查四个方向
                for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
                    nx, ny = x + dx, y + dy
                    if 0 <= nx < m and 0 <= ny < n and (grid[x][y] == '0' or grid[nx][ny] == grid[x][y]) and info[nx][ny] == 0:
                        tmp_opts.append((nx, ny))
                        info[nx][ny] = 1
            opts = tmp_opts
        
        res = 0
        # 计算最大非走廊相邻区域的大小
        for i in range(1, m - 1):
            for j in range(1, n - 1):
                if info[i][j] == 0:  # 未被标记的区域
                    tmp = 1
                    opts = [(i, j)]
                    info[i][j] = 1
                    while opts:
                        tmp_opts = []
                        for x, y in opts:
                            for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
                                nx, ny = x + dx, y + dy
                                if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == grid[x][y] and info[nx][ny] == 0:
                                    tmp_opts.append((nx, ny))
                                    info[nx][ny] = 1
                                    tmp += 1
                        opts = tmp_opts
                    res = max(res, tmp)
        
        return res
    

Explore

在广度优先搜索(BFS)中,通过从所有边界单元格以及所有'0'(走廊)单元格开始初始化队列,并标记这些单元格为已访问,确保了搜索的起点覆盖了所有可能与外界直接接触的区域。随后,在BFS过程中,对于队列中的每个单元格,检查其四周的邻接单元格。如果邻接单元格是同类型(即走廊或相同标识的其他单元格)且未被访问过,则将其加入队列并标记为已访问。这个过程递归地标记所有与初始走廊相连的区域。因此,通过逐层扩展这种标记,可以确保所有与走廊相连的区域都被正确地标记为已访问。

在初始化队列时,将所有边界单元格以及边界上的'0'(走廊)单元格加入队列是为了从所有可能与外部直接接触的点开始广度优先搜索。这样做是因为只有这些单元格可能直接或间接与外界接壳,其他非边界的'0'单元格虽然也是走廊,但它们在初始阶段被环绕在内部,不会直接接触到边界。通过从边界开始的BFS过程自然会访问到所有与这些边界走廊相连的内部走廊,因此无需在初始阶段将它们加入队列。这样做可以减少初始队列的大小,提高效率。

虽然走廊可能由多个不连续的部分组成,但通过从所有边界单元格和边界上的'0'(走廊)单元格开始BFS,可以确保这些不连续部分都能被访问。这是因为BFS算法从多个起点(边界单元格和走廊)开始,能够向内部扩展,逐步访问所有与这些起点相连的区域,包括那些内部但与边界走廊直接或间接相连的走廊部分。每当访问一个走廊单元格,就会检查其四周的单元格,如果邻接单元格也是走廊且未被访问,则会被加入到BFS的下一轮迭代中,这样逐步扩展可以覆盖所有连续或不连续的走廊部分。