Leetcode 827. 最大人工岛
在二维地图上, 0代表海洋, 1代表陆地,我们最多只能将一格 0 海洋变成 1变成陆地。
进行填海之后,地图上最大的岛屿面积是多少?(上、下、左、右四个方向相连的 1 可形成岛屿)
示例 1:
输入: [[1, 0], [0, 1]]
输出: 3
解释: 将一格0变成1,最终连通两个小岛得到面积为 3 的岛屿。
示例 2:
输入: [[1, 1], [1, 0]]
输出: 4
解释: 将一格0变成1,岛屿的面积扩大为 4。
示例 3:
输入: [[1, 1], [1, 1]]
输出: 4
解释: 没有0可以让我们变成1,面积依然为 4。
说明:
1 <= grid.length = grid[0].length <= 50
0 <= grid[i][j] <= 1
方法一:深度优先搜索【超时】
对于每个 0,将它变成 1,然后做一次深度优先搜索计算出连通块的大小。答案就是找到的最大连通块。如果没有 0,那么答案就是整个网格的大小。
时间复杂度:O(N^4),其中 N 是 grid 的长和宽。
空间复杂度:O(N^2),深度优先搜索需要的 stack 和 seen 的空间。
方法二:连通块大小【通过】
再上一个解法中,我们检查了每个 0。然而,我们也计算了每个组的大小,所以其实并不需要利用深度优先搜索重复计算所有的连通块。
我们可以通过记录连通块编号来解决这个问题,不同的连通块编号不同。这样,我们就可以累加不同编号的连通块面积和。
对于每个连通块,将所有格点赋值为 index 并记录他们的大小 area[index] = dfs(...)
。
然后对于每个 0,查看周围的邻居编号在 seen 并将这个区域的大小加入结果,改变 seen 的值。这就是当前节点的面积大小,在其中找到最大的。
为了解决没有 0 的情况,我们只需要记录之前计算的最大面积并输出即可。
class Solution:
def largestIsland(self, grid: List[List[int]]) -> int:
n = len(grid)
m = len(grid[0])
area = {} # 记录每一个连通块的面积
index = 2 # 为了避免和原始的1冲突,连通块标记从2开始
for row in range(n):
for col in range(m):
# 对连通块进行dfs遍历
# 每次遍历,把其周围的1进行index标记,同时记录连通块的面积
if grid[row][col] == 1:
area[index] = self.dfs(grid, row, col, index)
index += 1
ans = max(area.values() or [0]) # 防止全为0
for row in range(n):
for col in range(m):
if grid[row][col] == 0: # 对于每一个0,寻找其周围的连通块
visited = set() # 注意visited的位置
for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:
if 0 <= x < len(grid) and 0 <= y < len(grid[0]) and grid[x][y] > 1:
visited.add(grid[x][y])
# 更新最大面积,如果0周围存在连通块,
# 那么最大面积等于周围连通块面积和+1
ans = max(ans, 1 + sum(area[index] for index in visited))
return ans
# dfs遍历,对其周围为1的元素进行标记,并记录面积大小
def dfs(self, grid, row, col, index):
area = 1
grid[row][col] = index
for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:
if 0 <= x < len(grid) and 0 <= y < len(grid[0]) and grid[x][y] == 1:
area += self.dfs(grid, x, y, index)
return area
时间复杂度:O(N^2),其中 N 是 grid 的长度和宽度。
空间复杂度:O(N^2),深度优先搜索需要的数组 area 的额外空间。