题目
给你一个大小为 m x n 的二进制矩阵 grid 。
岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
岛屿的面积是岛上值为 1 的单元格的数目。
计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。
示例 1:
输入: grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出: 6
解释: 答案不应该是 11 ,因为岛屿只能包含水平或垂直这四个方向上的 1 。
示例 2:
输入: grid = [[0,0,0,0,0,0,0,0]]
输出: 0
提示:
m == grid.lengthn == grid[i].length1 <= m, n <= 50grid[i][j]为0或1
思路
该题也是经典的图遍历算法题,在遍历时碰到i,j位置为1的,通过4个方向去探寻边界,然后将搜寻到的位置设为0,防止重复计算。一般有DFS和BFS解法。
解法一: DFS
代码一: DFS
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
def dfs(grid, i, j):
if i < 0 or i >= nr or j < 0 or j >= nc or grid[i][j] == 0:
return 0
grid[i][j] = 0
return 1 + dfs(grid, i-1, j) + dfs(grid, i+1, j) + dfs(grid, i, j-1) + dfs(grid, i, j+1)
res = 0
nr = len(grid)
nc = len(grid[0])
for r in range(nr):
for c in range(nc):
if grid[r][c] == 1:
res = max(res, dfs(grid, r, c))
return res
解法二: DFS+栈
代码二: DFS+栈
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
nr = len(grid)
nc = len(grid[0])
res = 0
for r in range(nr):
for c in range(nc):
if grid[r][c] == 1:
cur = 0
stack = [(r, c)]
while stack:
cur_r, cur_c = stack.pop()
if cur_r < 0 or cur_r >= nr or cur_c < 0 or cur_c >= nc or grid[cur_r][cur_c] == 0:
continue
cur += 1
grid[cur_r][cur_c] = 0
for dr, dc in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
next_r, next_c = cur_r+dr, cur_c+dc
stack.append((next_r, next_c))
res = max(res, cur)
return res
解法三: BFS
代码三: BFS
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
nr = len(grid)
nc = len(grid[0])
res = 0
for r in range(nr):
for c in range(nc):
if grid[r][c] == 1:
cur = 0
neighbors = collections.deque([(r, c)])
while neighbors:
cur_r, cur_c = neighbors.popleft()
if cur_r < 0 or cur_r >= nr or cur_c < 0 or cur_c >= nc or grid[cur_r][cur_c] == 0:
continue
cur += 1
grid[cur_r][cur_c] = 0
for dr, dc in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
next_r, next_c = cur_r+dr, cur_c+dc
neighbors.append((next_r, next_c))
res = max(res, cur)
return res
解法四: 并查集
在基础上,使用max字段保存岛屿面积的最大值,在union时不断更新max最大值。 注意: 在初始化时,如果存在岛屿,需要将max初始化为1,否则在只有一个岛屿时,会计算出错。
代码四: 并查集
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
nr, nc = len(grid), len(grid[0])
if nr == 0:
return 0
uf = UnionFind(grid)
for r in range(nr):
for c in range(nc):
if grid[r][c] == 1:
for x, y in [(r+1, c), (r, c+1)]:
if x < nr and y < nc and grid[x][y] == 1:
uf.union(r*nc+c, x*nc+y)
return uf.max
class UnionFind:
def __init__(self, grid):
nr, nc = len(grid), len(grid[0])
self.max = 0
self.parent = [0] * (nr * nc)
self.size = [0] * (nr * nc)
for r in range(nr):
for c in range(nc):
# 针对单格岛,赋值parent[k]和size[k]
if grid[r][c] == 1:
self.parent[r * nc + c] = r * nc + c
# 初始化岛屿大小
self.size[r * nc + c] = 1
# 如果有岛屿,更新为单岛屿值
if self.max != 1:
self.max = 1
def find(self, x):
if self.parent[x] != x:
return self.find(self.parent[x])
return x
def union(self, x, y):
rootx = self.find(x)
rooty = self.find(y)
if rootx != rooty:
# x所在集合大小 >= y所在集合时,rooty挂到rootx上
if self.size[rootx] >= self.size[rooty]:
self.size[rootx] += self.size[rooty]
self.parent[rooty] = rootx
self.max = max(self.max, self.size[rootx])
# x所在集合大小 < y所在集合时,rootx挂到rooty上
else:
self.size[rooty] += self.size[rootx]
self.parent[rootx] = rooty
self.max = max(self.max, self.size[rooty])