99.岛屿数量
题目链接:99.岛屿数量
文档讲解:代码随想录
状态:不会
深搜
思路:
- 遍历网格,发现岛屿:我们需要遍历整个二维网格,检查每一个位置上的元素。如果在遍历过程中遇到陆地(值为1),这意味着我们发现了一个新的岛屿。
- 深度优先搜索,标记整个岛屿:为了标记整个岛屿,我们从这个陆地开始,使用深度优先搜索(DFS)将与之相连的所有陆地都标记为已访问过。这样可以确保同一个岛屿的所有部分都被访问到,不会重复计数。
- 统计岛屿数量:每当完成一次DFS遍历,就表示已经标记完一个完整的岛屿,所以岛屿数量加1。
- 继续遍历:继续遍历网格中的下一个位置,直到所有位置都被检查过。
题解:
public class Main {/*** 计算岛屿的数量** @param grid 输入的二维网格* @return 岛屿的数量*/public static int getNum(int[][] grid) {int count = 0; // 初始化岛屿数量为0int n = grid.length; // 网格的行数int m = grid[0].length; // 网格的列数for (int i = 0; i < n; i++) { // 遍历每一行for (int j = 0; j < m; j++) { // 遍历每一列if (grid[i][j] == 1) { // 如果当前位置是陆地dfs(grid, i, j); // 进行深度优先搜索,将连接的所有陆地标记count++; // 每标记完一个岛屿,岛屿数量加1}}}return count; // 返回岛屿数量}/*** 深度优先搜索(DFS)函数,用于标记连接的所有陆地** @param grid 网格* @param x 当前行* @param y 当前列*/public static void dfs(int[][] grid, int x, int y) {if (!inArea(grid, x, y)) { // 如果坐标不在网格范围内,直接返回return;}if (grid[x][y] != 1) { // 如果当前位置不是陆地(已经是水或者已经标记过),直接返回return;}grid[x][y] = 2; // 将当前陆地标记为2,表示已访问// 对当前陆地的上下左右四个方向进行递归搜索dfs(grid, x - 1, y);dfs(grid, x + 1, y);dfs(grid, x, y - 1);dfs(grid, x, y + 1);}/*** 判断坐标 (x, y) 是否在网格中** @param grid 网格* @param x 行坐标* @param y 列坐标* @return 坐标 (x, y) 是否在网格中*/static boolean inArea(int[][] grid, int x, int y) {return 0 <= x && x < grid.length && 0 <= y && y < grid[0].length;}/*** 主函数,读取输入并输出岛屿数量** @param args 命令行参数*/public static void main(String[] args) {Scanner scanner = new Scanner(System.in); // 创建扫描器用于读取输入int n = scanner.nextInt(); // 读取网格的行数int m = scanner.nextInt(); // 读取网格的列数int[][] graph = new int[n][m]; // 创建网格// 读取网格中的每一个元素for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {graph[i][j] = scanner.nextInt();}}// 输出岛屿的数量System.out.println(getNum(graph));}
}
广搜
思路:
使用 BFS 进行遍历,从每个未访问过的陆地开始,进行岛屿的搜索。
使用一个队列来存储待处理的陆地节点,并使用一个二维数组来标记已访问过的节点,以避免重复计数。
- 初始化:定义方向数组,包括上、下、左、右四个方向的移动。使用队列存储起始节点,并将起始节点标记为已访问。
- BFS遍历:从队列中取出节点,检查其四个相邻方向的节点:
- 如果相邻节点是未访问过的陆地(值为 1),则将其加入队列并标记为已访问。
- 继续该过程直到队列为空,表示一个完整的岛屿已经被遍历完毕。
- 计数:每当从主函数的双重循环中发现未访问的陆地(即值为 1 的格子),则调用 BFS 进行扩展,并将岛屿计数加一。
题解:
/*** 使用BFS计算岛屿数量** @param grid 输入的二维网格* @param visited 访问标记数组* @param x 当前节点行坐标* @param y 当前节点列坐标*/static void bfs(int[][] grid, boolean[][] visited, int x, int y) {int n = grid.length;int m = grid[0].length;// 方向数组:下、右、上、左int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};Deque<int[]> deque = new LinkedList<>();deque.addLast(new int[]{x, y}); // 将起始节点加入队列visited[x][y] = true; // 标记起始节点为已访问while (!deque.isEmpty()) {int[] point = deque.pollFirst(); // 取出队列首个节点int curX = point[0];int curY = point[1];// 遍历当前节点的四个方向for (int i = 0; i < 4; i++) {int newX = curX + dir[i][0];int newY = curY + dir[i][1];// 检查新位置是否在网格范围内,并且是未访问的陆地if (newX >= 0 && newX < n && newY >= 0 && newY < m && grid[newX][newY] == 1 && !visited[newX][newY]) {deque.addLast(new int[]{newX, newY}); // 将新位置加入队列visited[newX][newY] = true; // 标记新位置为已访问}}}}/*** 主函数,读取输入并输出岛屿数量** @param args 命令行参数*/public static void main(String[] args) {Scanner scanner = new Scanner(System.in); // 创建扫描器用于读取输入int n = scanner.nextInt(); // 读取网格的行数int m = scanner.nextInt(); // 读取网格的列数int[][] graph = new int[n][m]; // 创建网格// 读取网格中的每一个元素for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {graph[i][j] = scanner.nextInt();}}boolean[][] visited = new boolean[n][m];int count = 0;// 遍历每个位置,如果是未访问过的陆地(值为1),则调用bfs进行岛屿扩展,并计数for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (graph[i][j] == 1 && !visited[i][j]) {bfs(graph, visited, i, j); // 对未访问过的陆地进行BFS搜索count++; // 计数岛屿数量}}}// 输出岛屿的数量
// System.out.println(getNum(graph));System.out.println(count);}
100.岛屿的最大面积
题目链接:100.岛屿的最大面积
文档讲解:代码随想录
状态:磕磕绊绊做出来了
思路:
在上一题的基础上,每遍历陆地中的一个格子,面积加一,返回最大面积。
dfs题解:
public class Main {// 定义方向数组,表示右、下、左、上四个方向public static int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};/*** 深度优先搜索 (DFS) 方法,计算从 (x, y) 开始的岛屿面积** @param grid 二维数组表示的网格* @param visited 二维数组标记是否访问过* @param x 当前坐标的 x 轴位置* @param y 当前坐标的 y 轴位置* @return 从 (x, y) 开始的岛屿面积*/public static int dfs(int[][] grid, boolean[][] visited, int x, int y) {// 检查是否越界、是否已经访问过、是否是水域if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length || visited[x][y] || grid[x][y] == 0) {return 0;}// 将当前格子标记为已访问,并将其面积记为 1int sum = 1;visited[x][y] = true;// 遍历四个方向,并递归搜索相邻格子for (int i = 0; i < 4; i++) {int newX = x + dir[i][0];int newY = y + dir[i][1];sum += dfs(grid, visited, newX, newY);}return sum;}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 读取网格的行数和列数int n = scanner.nextInt();int m = scanner.nextInt();// 初始化网格并读取值int[][] grid = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {grid[i][j] = scanner.nextInt();}}// 初始化访问标记数组boolean[][] visited = new boolean[n][m];int maxArea = 0;// 遍历网格中的每一个格子for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 如果当前格子是岛屿且未被访问过,则计算从该格子开始的岛屿面积if (!visited[i][j] && grid[i][j] == 1) {maxArea = Math.max(maxArea, dfs(grid, visited, i, j));}}}// 输出最大的岛屿面积System.out.println(maxArea);}
}
bfs题解:
public static int bfs(int[][] grid) {// 使用双端队列来存储待访问的节点Deque<int[]> deque = new LinkedList<>();// 获取网格的行数和列数int n = grid.length;int m = grid[0].length;// 用于记录最大的岛屿面积int maxArea = 0;// 遍历网格中的每一个格子for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 如果格子中的值为1,表示这是一个岛屿的一部分if (grid[i][j] == 1) {// 初始化当前岛屿的面积int sum = 1;// 将当前格子标记为已访问grid[i][j] = 2;// 将当前格子的坐标加入队列deque.addLast(new int[]{i, j});// 进行广度优先搜索while (!deque.isEmpty()) {// 从队列中取出一个格子的坐标int[] point = deque.pollFirst();int x = point[0];int y = point[1];// 遍历该格子周围的四个方向for (int k = 0; k < 4; k++) {int newX = x + dir[k][0];int newY = y + dir[k][1];// 检查新的坐标是否在网格范围内,并且该格子是否未被访问过if (newX >= 0 && newX < n && newY >= 0 && newY < m && grid[newX][newY] == 1) {// 将新的格子标记为已访问grid[newX][newY] = 2;// 将新的格子的坐标加入队列deque.addLast(new int[]{newX, newY});// 增加当前岛屿的面积sum++;}}}// 更新最大的岛屿面积maxArea = Math.max(maxArea, sum);}}}// 返回最大的岛屿面积return maxArea;}