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

图论——岛屿数量

题目:给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。

岛屿数量是经典的 深度优先搜索(DFS)和广度优先搜索(BFS) 算法题,核心思路:
1.遍历二维网格的每一个格子;
2.遇到陆地'1'时,说明找到一座新岛屿,岛屿数量+1;
3.立即把这座岛屿所有相连的陆地全部标记为水'0'(避免重复统计);
4.最终统计的总数就是岛屿数量。

深度优先搜索(DFS)递归实现
public class NumberOfIslands {

public int numIslands(char[][] grid) {// 边界判断:网格为空直接返回0if (grid == null || grid.length == 0) {return 0;}int row = grid.length;    // 网格行数int col = grid[0].length; // 网格列数int count = 0;            // 岛屿数量// 遍历每一个格子for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {// 找到未被访问的陆地if (grid[i][j] == '1') {count++; // 岛屿+1// DFS:把当前岛屿所有陆地标记为水dfs(grid, i, j);}}}return count;
}// DFS递归函数:标记所有相连的陆地为水
private void dfs(char[][] grid, int i, int j) {int row = grid.length;int col = grid[0].length;// 递归终止条件:越界 或 当前是水,直接返回if (i < 0 || i >= row || j < 0 || j >= col || grid[i][j] == '0') {return;}// 标记当前陆地为水(已访问)grid[i][j] = '0';// 递归搜索 上下左右 四个方向dfs(grid, i - 1, j); // 上dfs(grid, i + 1, j); // 下dfs(grid, i, j - 1); // 左dfs(grid, i, j + 1); // 右
}// 测试示例
public static void main(String[] args) {NumberOfIslands solution = new NumberOfIslands();char[][] grid = {{'1','1','0','0','0'},{'1','1','0','0','0'},{'0','0','1','0','0'},{'0','0','0','1','1'}};System.out.println("岛屿数量:" + solution.numIslands(grid)); // 输出 3
}

}

代码解释
1.主函数:双重循环遍历网格所有格子,遇到陆地就计数 + 1,并启动 DFS;
2.DFS 函数:

  • 先判断是否越界 / 是水,是则终止递归;
  • 把当前陆地改为水(标记已访问);
  • 递归遍历上下左右四个相邻格子。

关键点解释:

1. 递归遍历只是把与这片岛屿相连的陆地标记为水,而不是把整个网格全淹,因为dfs的if条件一遇到水grid[i][j]=='0'退出递归,所以,DFS只淹当前连通的那一块

2. grid==null||grid.length ==0的两个判断完全不一样,缺一不可

  • grid==null
    防:变量根本没指向任何数组
    char[][] grid = null;
    意思是:这里空空如也,连数组的影子都没有。
    如果你不判断,直接去写 grid.length,直接报空指针错误,程序挂掉!

  • 2.grid.length == 0
    防:有数组,但数组是空的(一行都没有)
    意思是:有一个空箱子,但箱子里什么都没有。
    这时候 grid 不是 null,但 grid.length 是 0。

3. 为什么要写成 || ?
因为 || 是短路或:

  • 先判断 grid == null
  • 如果是 true,后面的 grid.length 根本不会执行
  • 完美避免空指针崩溃!

总结:

  1. grid == null:防空引用(没数组)
  2. grid.length == 0:防空数组(有数组,没内容)
  3. 两个一起写:才是真正的安全、健壮、不会崩溃!

另外注意越界判断时
i>=row,j>=col,不要漏掉'='因为i是下标,从0开始,到row-1结束,同理j也是。

补充:
Java里没有指针,但Java里的数组、对象本质都是引用,判断引用是否为空,就是用 ==null

在 Java 里:

  • 基本类型(int/char/boolean)不可能为 null
  • 数组、对象、字符串 都是引用类型完全可以为 null

空指针访问异常是习惯叫法,实际上指的是空引用访问异常

http://www.jsqmd.com/news/654863/

相关文章:

  • 牛客Top200---合并区间 (Java实战:从图解到代码的完整通关)
  • 别再到处找了!2024最新银河麒麟V10全版本(飞腾/龙芯/兆芯)官方下载与安装保姆级教程
  • 2026兰州好吃的涮羊肉指南:滩羊肉店推荐-清真羊胜记铜锅涮肉・爆肚 (天水路店),好吃不踩雷 - 栗子测评
  • 打通业财壁垒,破解“两张皮”难题——融智天费用控制系统业财一体化体验 - 业财科技
  • 可扩散模型(Diffusion Models)详解:从原理到应用
  • Qt桌面应用现代化改造:用AdvancedDockingSystem打造可拖拽停靠的‘IDE级’主界面(搭配自制Ribbon菜单)
  • 2025年500米分辨率的地形粗糙度栅格数据(全球/全国)
  • django-push-notifications错误处理与调试:解决常见推送问题
  • 农历计算的技术挑战与lunar-javascript的解决方案:构建高效的传统历法系统
  • 如何理解Tomcat、Servlet、Catanalina的关系
  • 5分钟掌握OpenTwins数字孪生开源平台:从零到实战部署指南
  • 3个步骤教你掌握百度网盘秒传脚本:永久分享文件不再失效
  • 2026年炒外汇交易平台排行与推荐指南:从技术到市场口碑一览 - 速递信息
  • LDO的实战指南:从参数解析到稳定设计
  • 刚柔并济,适配多样需求——融智天费用控制系统灵活管控体验 - 业财科技
  • AnyCrawl AI数据提取:使用LLM智能解析网页内容
  • 深入解析SAP ALV选择模式的实现与应用场景
  • 八大网盘直链解析工具终极指南:告别下载限速的完整解决方案
  • Unity C#脚本动态控制Material和Shader的5种方法详解(附完整代码示例)
  • 支付宝立减金如何回收?深入解读闲置原因与回收注意事项 - 团团收购物卡回收
  • 因果AI:从相关到因果,下一代决策智能的核心
  • 万爱通礼品卡回收:线上回收让闲置卡片变现更简单 - 团团收购物卡回收
  • React SSR 渲染性能优化与缓存机制
  • 从源码到实战:剖析RocketMQ invokeSync超时异常的深层诱因与根治策略
  • PrimeNG性能优化指南:大型应用加载速度提升50%的终极方案
  • Java虚拟机JVM内存模型深度解析
  • EPC发布用于机器人和轻型电动车的5kW氮化镓三相逆变器
  • 如何利用Letta实现自动化API文档与使用示例生成:完整指南
  • Python百度搜索API:3分钟实现免费搜索引擎集成的完整指南
  • 永辉超市卡安全回收方式 - 京顺回收