当前位置: 首页 > news >正文

Day51--图论--99. 岛屿数量(卡码网),100. 岛屿的最大面积(卡码网)

Day51–图论–99. 岛屿数量(卡码网),100. 岛屿的最大面积(卡码网)

本篇重点,在于理解深搜和广搜遍历顺序的不同,以及深搜广搜对应的坑点。

给出了打印遍历顺序的代码,可以打印出来遍历点直观感受一下。

可以看到,DFS就是不撞南墙不回头;BFS就是像水波纹一样一层一层荡漾开来。

99. 岛屿数量(卡码网)

方法:深搜

思路:

本题思路,是遇到一个没有遍历过的陆地,计数器就加一,然后把该节点所能遍历到的陆地都标记上。

在遇到标记过的陆地节点或海洋节点的时候直接跳过。 这样计数器就是最终岛屿的数量。

import java.util.*;public class Main {// 四个方向:右、下、左,上private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};private static void dfs(int[][] grid, boolean[][] visited, int x, int y) {// 四个方向都遍历一遍for (int i = 0; i < 4; i++) {int nextX = x + dir[i][0];int nextY = y + dir[i][1];// 检查是否越界if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {continue;}// 如果未访问且是陆地(1),则继续DFSif (!visited[nextX][nextY] && grid[nextX][nextY] == 1) {visited[nextX][nextY] = true;dfs(grid, visited, nextX, nextY);}}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();int[][] grid = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {grid[i][j] = in.nextInt();}}// 访问标记数组boolean[][] visited = new boolean[n][m];// 计数器int count = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 发现未访问的陆地,岛屿数量加1,并开始DFS标记所有相连的陆地if (!visited[i][j] && grid[i][j] == 1) {visited[i][j] = true;count++;dfs(grid, visited, i, j);}}}System.out.println(count);in.close();}
}

遍历顺序:

DFS访问顺序:1  2  0  0  0 4  3  0  0  0 0  0  5  0  0 0  0  0  6  7 

方法:广搜

思路:

只要加入队列就代表走过,就需要标记,而不是从队列拿出来的时候再去标记走过。

import java.util.*;public class Main {// 四个方向:右、下、左,上private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};// 广搜private static void bfs(int[][] grid, boolean[][] visited, int x, int y) {Deque<int[]> que = new ArrayDeque<>();// 存储节点坐标que.offer(new int[] {x, y});// 加入队列后立即标记为已访问visited[x][y] = true;while (!que.isEmpty()) {int[] cur = que.poll();int curX = cur[0];int curY = cur[1];// 四个方向都遍历一遍for (int i = 0; i < 4; i++) {int nextX = curX + dir[i][0];int nextY = curY + dir[i][1];// 检查是否越界if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {continue;}// // 如果是未访问的陆地,则加入队列并标记if (!visited[nextX][nextY] && grid[nextX][nextY] == 1) {que.offer(new int[] {nextX, nextY});visited[nextX][nextY] = true;}}}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();int[][] grid = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {grid[i][j] = in.nextInt();}}// 访问标记数组boolean[][] visited = new boolean[n][m];// 计数器int count = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 发现未访问的陆地,岛屿数量加1,并开始BFS标记所有相连的陆地if (!visited[i][j] && grid[i][j] == 1) {count++;bfs(grid, visited, i, j);}}}System.out.println(count);in.close();}
}

遍历顺序:

DFS访问顺序:1  2  0  0  0 4  3  0  0  0 0  0  5  0  0 0  0  0  6  7 
BFS访问顺序:1  2  0  0  0 3  4  0  0  0 0  0  5  0  0 0  0  0  6  7 

遍历顺序打印

思路:

可以复制代码,修改代码中的矩阵,打印出来,直观看看每一步都是怎么走的。

import java.util.LinkedList;
import java.util.Queue;public class TraversalOrder {// 四个方向:右、下、左,上private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};private static int count;// DFS遍历并记录访问顺序private static void dfs(int[][] grid, int[][] order, int x, int y) {for (int i = 0; i < 4; i++) {int nextx = x + dir[i][0];int nexty = y + dir[i][1];if (nextx >= 0 && nextx < grid.length && nexty >= 0 && nexty < grid[0].length) {if (grid[nextx][nexty] == 1 && order[nextx][nexty] == 0) {count++;order[nextx][nexty] = count;dfs(grid, order, nextx, nexty);}}}}// BFS遍历并记录访问顺序private static void bfs(int[][] grid, int[][] order, int x, int y) {Queue<int[]> queue = new LinkedList<>();queue.offer(new int[]{x, y});count++;order[x][y] = count;while (!queue.isEmpty()) {int[] cur = queue.poll();int curx = cur[0];int cury = cur[1];for (int i = 0; i < 4; i++) {int nextx = curx + dir[i][0];int nexty = cury + dir[i][1];if (nextx >= 0 && nextx < grid.length && nexty >= 0 && nexty < grid[0].length) {if (grid[nextx][nexty] == 1 && order[nextx][nexty] == 0) {count++;order[nextx][nexty] = count;queue.offer(new int[]{nextx, nexty});}}}}}// 打印访问顺序矩阵private static void printOrder(int[][] order) {for (int i = 0; i < order.length; i++) {for (int j = 0; j < order[0].length; j++) {System.out.printf("%2d ", order[i][j]);}System.out.println();}}public static void main(String[] args) {// 初始化给定的矩阵int[][] grid = {{1, 1, 1, 1, 1},{1, 1, 1, 1, 1},{1, 1, 1, 1, 1},{1, 1, 1, 1, 1},{1, 1, 1, 1, 1}};int n = grid.length;int m = grid[0].length;// 演示DFS访问顺序System.out.println("DFS访问顺序:");int[][] dfsOrder = new int[n][m];count = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (grid[i][j] == 1 && dfsOrder[i][j] == 0) {count++;dfsOrder[i][j] = count;dfs(grid, dfsOrder, i, j);}}}printOrder(dfsOrder);// 演示BFS访问顺序System.out.println("\nBFS访问顺序:");int[][] bfsOrder = new int[n][m];count = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (grid[i][j] == 1 && bfsOrder[i][j] == 0) {bfs(grid, bfsOrder, i, j);}}}printOrder(bfsOrder);}
}

目前代码打印效果

DFS访问顺序:
1  2  3  4  5 
22 23 24 25  6 
21 20 19 18  7 
14 15 16 17  8 
13 12 11 10  9 
BFS访问顺序:
1  2  4  7 11 
3  5  8 12 16 
6  9 13 17 20 
10 14 18 21 23 
15 19 22 24 25 

可以看到,DFS就是不撞南墙不回头;BFS就是像水波纹一样一层一层荡漾开来。

100. 岛屿的最大面积(卡码网)

方法:深搜

思路:

在dfs递归的时候统计,每一层递归向上返回本次遍历到的岛屿数。

主函数里的循环,每次都是遇到一个新的岛屿,所以在主函数里,dfs回来之后,刷新maxLand。

import java.util.*;public class Main {// 四个方向:右、下、左,上private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};private static int dfs(int[][] grid, boolean[][] visited, int x, int y) {// 坐标为x,y的本节点int sum = 1;// 四个方向都遍历一遍for (int i = 0; i < 4; i++) {int nextX = x + dir[i][0];int nextY = y + dir[i][1];// 检查是否越界if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {continue;}// 如果未访问且是陆地(1),则继续DFSif (!visited[nextX][nextY] && grid[nextX][nextY] == 1) {visited[nextX][nextY] = true;// 加上从这个节点出发,深搜到的所有节点sum += dfs(grid, visited, nextX, nextY);}}// 返回给上一层return sum;}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();int[][] grid = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {grid[i][j] = in.nextInt();}}// 访问标记数组boolean[][] visited = new boolean[n][m];int maxLand = 0;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 发现未访问的陆地,岛屿数量加1,并开始DFS标记所有相连的陆地if (!visited[i][j] && grid[i][j] == 1) {visited[i][j] = true;// 每次从这里进去的,是一整个岛屿int land = dfs(grid, visited, i, j);// 刷新最大岛屿面积maxLand = Math.max(maxLand, land);}}}System.out.println(maxLand);in.close();}
}

方法:深搜

思路:

全局变量maxLand和count。

主函数里的循环,每次都是遇到一个新的岛屿,所以在主函数里,dfs之前,重置count=0,dfs回来之后,刷新maxLand。

import java.util.*;public class Main {// 四个方向:右、下、左,上private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};private static int maxLand = 0;private static int count = 0;private static void dfs(int[][] grid, boolean[][] visited, int x, int y) {count++;// 四个方向都遍历一遍for (int i = 0; i < 4; i++) {int nextX = x + dir[i][0];int nextY = y + dir[i][1];// 检查是否越界if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {continue;}// 如果未访问且是陆地(1),则继续DFSif (!visited[nextX][nextY] && grid[nextX][nextY] == 1) {visited[nextX][nextY] = true;dfs(grid, visited, nextX, nextY);}}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();int[][] grid = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {grid[i][j] = in.nextInt();}}// 访问标记数组boolean[][] visited = new boolean[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 发现未访问的陆地,岛屿数量加1,并开始DFS标记所有相连的陆地if (!visited[i][j] && grid[i][j] == 1) {visited[i][j] = true;count = 0;dfs(grid, visited, i, j);maxLand = Math.max(res, count);}}}System.out.println(maxLand);in.close();}
}

方法:广搜

思路:

同上,接着用全局变量的方法,使用maxLand和count计数。

当队列que出队的时候,count++;

当回到主函数的时候,刷新maxLand。

import java.util.*;public class Main {// 四个方向:右、下、左,上private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};private static int maxLand = 0;private static int count = 0;// 广搜private static void bfs(int[][] grid, boolean[][] visited, int x, int y) {Deque<int[]> que = new ArrayDeque<>();// 存储节点坐标que.offer(new int[] {x, y});// 加入队列后立即标记为已访问visited[x][y] = true;while (!que.isEmpty()) {// 每次弹出队列的时候,节点+1,岛屿面积++count++;int[] cur = que.poll();int curX = cur[0];int curY = cur[1];// 四个方向都遍历一遍for (int i = 0; i < 4; i++) {int nextX = curX + dir[i][0];int nextY = curY + dir[i][1];// 检查是否越界if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {continue;}// // 如果是未访问的陆地,则加入队列并标记if (!visited[nextX][nextY] && grid[nextX][nextY] == 1) {que.offer(new int[] {nextX, nextY});visited[nextX][nextY] = true;}}}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();int[][] grid = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {grid[i][j] = in.nextInt();}}// 访问标记数组boolean[][] visited = new boolean[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {// 发现未访问的陆地,岛屿数量加1,并开始BFS标记所有相连的陆地if (!visited[i][j] && grid[i][j] == 1) {count = 0;bfs(grid, visited, i, j);maxLand = Math.max(maxLand, count);}}}System.out.println(maxLand);in.close();}
}
http://www.dtcms.com/a/329317.html

相关文章:

  • 互联网大厂Java求职面试实录:Spring Boot到微服务与AI的技术问答
  • day50 图论基础 卡码网98. 所有可达路径
  • Day52--图论--101. 孤岛的总面积(卡码网),102. 沉没孤岛(卡码网),103. 水流问题(卡码网),104. 建造最大岛屿(卡码网)
  • java学习 leetcode 二分查找 图论
  • 【25-cv-09259】Keith律所代理Macneil Studio发起TRO狙击!
  • AI产品:从功能固化到动态进化
  • 职场与生活如何在手机中共存?(二)
  • 斯坦福大学联合项目 | ReKep 方法论文解读:机器人操作中关系关键点约束的时空推理
  • AutoCAD 各版本与插件合集详解:Architecture、Plant 3D、Civil 3D 等
  • 猿大师中间件:Chrome网页内嵌PhotoShop微信桌面应用程序
  • [Linux]学习笔记系列 -- [arm][process]
  • Node.js面试题及详细答案120题(16-30) -- 核心模块篇
  • AXIOS 入门
  • 2025 环法战车科技对决!维乐 Angel Glide定义舒适新标
  • 2025年最新Java后端场景面试题(大厂真题+解析)
  • 低空经济相关技术在智能建造与建筑行业有什么用处?
  • 图论理论部分
  • wps--设置
  • 读《精益数据分析》:双边市场的核心指标分析
  • 宿舍限电模块在宿舍改造项目中功能选择
  • Java数据库编程之【Derby数据库】【JDBC创建数据库例程】【三】
  • 【Java web】HTTP 与 Web 基础教程
  • el-select如何获取到filterable过滤后的数据;el-select全选与filterable过滤组合使用;
  • (30)python+playwright自动化测试处理日历时间控件-下
  • 解决H616编译路径问题
  • 第一章 OkHttp 是怎么发出一个请求的?——整体流程概览
  • dp+e2e论文词汇积累自查
  • Microsoft Whiteboard功能深度解析:企业协作与创意管理的智能画布
  • ce找基地址简单版
  • 如何准备一场技术演讲