LeetCode 695-岛屿的最大面积

109 阅读3分钟

题目

给你一个大小为 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.length
  • n == grid[i].length
  • 1 <= m, n <= 50
  • grid[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])