leetcode
leetcode 601 ~ 650
不同岛屿的数量

不同岛屿的数量

难度:

标签:

题目描述

代码结果

运行时间: 55 ms, 内存: 16.3 MB


/*
 * 题目思路:
 * 使用Java Stream API实现找到不同岛屿数量的方法稍显复杂,因为Stream更适合处理非递归的、无状态的操作。
 * 但我们依然可以借助Stream来进行初始化、遍历,并在其中调用DFS方法。
 */
import java.util.*;
import java.util.stream.*;
 
public class NumberOfDistinctIslandsStream {
    private static final int[] dx = {0, 1, 0, -1};
    private static final int[] dy = {1, 0, -1, 0};
 
    public int numDistinctIslands(int[][] grid) {
        if (grid == null || grid.length == 0) return 0;
        Set<String> islands = new HashSet<>();
        boolean[][] visited = new boolean[grid.length][grid[0].length];
 
        IntStream.range(0, grid.length).forEach(i ->
            IntStream.range(0, grid[0].length).forEach(j -> {
                if (grid[i][j] == 1 && !visited[i][j]) {
                    StringBuilder shape = new StringBuilder();
                    dfs(grid, visited, i, j, shape, 'o');
                    islands.add(shape.toString());
                }
            })
        );
        return islands.size();
    }
 
    private void dfs(int[][] grid, boolean[][] visited, int x, int y, StringBuilder shape, char dir) {
        if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length || grid[x][y] == 0 || visited[x][y]) return;
        visited[x][y] = true;
        shape.append(dir);
        for (int i = 0; i < 4; i++) {
            dfs(grid, visited, x + dx[i], y + dy[i], shape, (char) ('0' + i));
        }
        shape.append('b');
    }
}
 

解释

方法:

该题目的目标是找出二维网格中不同的岛屿数量,其中岛屿由相邻(上下左右)的1组成。解题思路是通过深度优先搜索(DFS)遍历每个岛屿,同时将遍历过的岛屿上的1修改为0,以防止重复计数。对于每个岛屿,记录其形状的相对坐标。将每个岛屿的形状存入列表中,最后对列表中的形状进行排序,并通过比较相邻形状来统计不同岛屿的数量。

时间复杂度:

O(MN)

空间复杂度:

O(MN)

代码细节讲解

🦆
为什么在处理岛屿的形状时,使用相对坐标而不是绝对坐标?这种方式对于确定不同岛屿的数量有何优势?
使用相对坐标而不是绝对坐标可以确保岛屿的比较是基于其结构而不是位置。这意味着即使两个岛屿在网格中的不同位置,只要它们的形状和结构相同,它们就被认为是相同的岛屿。这种方法使得岛屿的比较独立于它们在网格中的具体位置,能够更准确地统计不同岛屿的数量。
🦆
在`tmp`列表中连续添加坐标偏移值的操作是否有可能导致列表增长得过大,从而影响性能?有没有更有效的方式来处理这一点?
确实,`tmp`列表在遍历大型岛屿时可能会增长得非常大,这会消耗大量内存并可能影响性能。为了优化,可以考虑使用哈希表来存储访问过的坐标,这样可以在不重复存储相同坐标的情况下,有效地检查和标记已访问的位置。此外,可以探索使用更紧凑的数据结构来存储坐标信息,如使用二元组代替单独的列表元素。
🦆
代码中的`while`循环依赖于`tmp`列表的长度动态变化。这种设计是否可能导致逻辑错误或效率问题?能否通过其他数据结构如队列来优化这一过程?
依赖于`tmp`列表长度的动态变化确实可能导致逻辑复杂和效率低下,因为它要求在循环内部修改列表同时又遍历该列表。使用队列可以优化这一过程。通过队列,可以实现先进先出的顺序,每次从队列的前端取出当前节点进行处理,并将新发现的节点加入队列的后端。这样可以使代码逻辑更清晰,且在性能上更为稳定。
🦆
在DFS过程中,代码没有显式地检查列边界`c`的值是否有效(例如`c-1`和`c+1`是否可能越界),这是否会导致运行时错误?
列边界的检查是非常重要的,如果没有进行适当的边界检查,代码可能会尝试访问数组外的元素,从而导致运行时错误。在代码中应该添加对`c-1`和`c+1`的检查,确保这些值在有效范围内,从而避免越界错误。这不仅能保证程序的稳定性,还能防止潜在的安全风险。

相关问题

岛屿数量

给你一个由 '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

 

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 300
  • grid[i][j] 的值为 '0''1'

不同岛屿的数量 II

不同岛屿的数量 II