新闻详情

新闻详情

首页 / 资讯中心 / 详情

岛屿数量:DFS + vis 数组为什么不会重复计数

发布时间:2026/10/2 1:42:31来源:尧图网络
岛屿数量:DFS + vis 数组为什么不会重复计数
题目链接200. 岛屿数量 - 力扣这题给一个只包含 1 和 0 的二维网格1 表示陆地。0 表示水。只有上下左右相邻的陆地才算连在一起斜着不算。要求我们求出网格里有多少座岛。这题表面是在数岛实际上是在数“连通块”一整片上下左右连通的陆地只能算一座岛。核心思路遍历整个矩阵。如果当前位置是水跳过。如果当前位置是陆地但之前已经访问过说明它已经属于某座岛也跳过。只有当当前位置满足是陆地并且没有访问过才说明我们发现了一座新的岛屿。这时做两件事ret岛屿数量加一。从当前位置开始 DFS把这座岛上所有连通的陆地都标记成已访问。这样后面外层循环再扫到同一座岛的其他陆地时因为它们已经被 vis 标记过就不会重复计数。为什么 ret 放在 DFS 前外层循环扫到一个“未访问陆地”时它就是一座新岛的入口。注意这里的入口不一定是岛的左上角也不一定是什么特殊位置。只要它还没访问过就说明前面没有任何一次 DFS 处理过它所在的岛。所以此时可以直接 ret。然后再调用 dfs(grid, i, j)把这座岛整体标记掉。可以把两层逻辑分开看外层循环负责发现新岛入口。DFS负责从入口出发把同一座岛全部处理完。DFS 函数负责什么这篇代码用的是 vis 数组不是直接修改 grid。所以所谓“把岛变成海洋”在这份代码里更准确地说是把同一座岛上的陆地全部标记为“已访问”。也就是vis[i][j] true;然后向上下左右四个方向继续找陆地。四个方向可以用两个数组表示int[] dx {0, 0, -1, 1};int[] dy {1, -1, 0, 0};对应的顺序是右、左、上、下。每次从当前位置 (i, j) 走到新位置int x i dx[k];int y j dy[k];只有当新位置同时满足下面几个条件时才继续递归坐标没有越界没有访问过grid[x][y] 1也就是它确实是陆地。Java 代码class Solution {boolean[][] vis;int m, n;int[] dx {0, 0, -1, 1};int[] dy {1, -1, 0, 0};public int numIslands(char[][] grid) {m grid.length;n grid[0].length;vis new boolean[m][n];int ret 0;for (int i 0; i m; i) {for (int j 0; j n; j) {if (!vis[i][j] grid[i][j] 1) {ret;dfs(grid, i, j);}}}return ret;}public void dfs(char[][] grid, int i, int j) {vis[i][j] true;for (int k 0; k 4; k) {int x i dx[k];int y j dy[k];if (x 0 x m y 0 y n !vis[x][y] grid[x][y] 1) {dfs(grid, x, y);}}}}看图理解递归展开先看运行结果再看递归展开和逻辑展开这张图重点看两个地方。第一个是左边代码里的 dfs(grid, x, y)。当递归走到一个新的陆地位置时第一件事就是把它标记为已访问vis[i][j] true;也就是说这个位置以后不会再次成为“新岛入口”。第二个是右边样例里的扫描顺序。外层循环仍然会一格一格往后扫但扫到已经访问过的陆地时条件!vis[i][j] grid[i][j] 1不会再成立。这就是为什么同一座岛不会重复计数。一个容易混的细节原地修改 grid 和使用 vis 数组本质上都是为了避免重复访问。有些题解会在 DFS 时把陆地改成水grid[i][j] 0;这相当于“访问过的陆地不再当陆地看”。而这篇代码没有改原数组而是用了 visvis[i][j] true;所以理解时不要被“变成海洋”这句话卡住。这里真正的意思是这块陆地已经被当前这次 DFS 处理过了后面不能再重复处理。易错点斜对角不算连通。题目只允许上下左右相邻所以方向数组只有四个方向。ret 要放在发现新岛入口时。也就是外层循环遇到“未访问陆地”时加一而不是 DFS 每走到一个陆地就加一。vis[i][j] true 不需要回溯。这不是排列组合那种“选完还要撤销”的 DFS。这里访问过就是真的处理完了不能回退成没访问。坐标合法性要先判断。访问 grid[x][y] 和 vis[x][y] 前必须先保证 x、y 没越界。总结这题的关键不是“会不会写 DFS”而是想清楚 DFS 在这里承担的任务。外层循环负责找入口。DFS 负责从入口出发把同一座岛的所有陆地都标记为已访问。所以记住相信你的递归函数它可以把当前岛处理完。不理解时先手动展开一两个样例。等手动展开通了再把这个过程抽象成 DFS。当你能理解这一点这类岛屿问题比如岛屿最大面积、图像渲染、被围绕的区域思路就会顺很多。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

STM32烧录三大方式原理与实战选型指南 2026/10/2 2:35:09

STM32烧录三大方式原理与实战选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Java项目实战:从零搭建一个高并发系统 2026/10/2 2:35:03

Java项目实战:从零搭建一个高并发系统

三年前老板扔给我一个需求:做一个能扛住十万并发的秒杀系统。我当时只会写CRUD,硬着头皮上了。上线第一周,系统崩了四次,每次都是半夜被叫起来救火。一年后,这套系统稳如老狗,QPS峰值跑到十二万。回头看&am…

阅读更多 →
HarmonyOS 7 EasyGo + ArkUI Navigation:平行视界导航模式的列表选中态、右栏路由栈与全局返回收口【鸿蒙心迹】 2026/10/2 2:35:03

HarmonyOS 7 EasyGo + ArkUI Navigation:平行视界导航模式的列表选中态、右栏路由栈与全局返回收口【鸿蒙心迹】

这次不写“平行视界怎么打开”,而是把问题往真实阅读类 App 里再推进一步:左边文章列表固定,右边详情可以继续点相关推荐;当右栏已经压入第二层详情以后,用户执行全局返回,应该只退右栏,不应该把…

阅读更多 →
HarmonyOS 7 状态手记 05|页面跳转带好状态 2026/10/2 2:35:03

HarmonyOS 7 状态手记 05|页面跳转带好状态

做 HarmonyOS 7 页面时,最容易把人绕进去的往往不是布局,而是“这个值到底该放哪儿”。列表页进入详情再返回 看起来只是几行代码,真接进项目后,经常会遇到 UI 不刷新、返回页面数据变旧、弹窗取消后值却被改掉,或者一…

阅读更多 →
离线会议纪要软件哪个好?2026年实测推荐这几款不联网的工具 2026/10/2 2:35:03

离线会议纪要软件哪个好?2026年实测推荐这几款不联网的工具

开完会,整理纪要要花一晚上?录音丢进去,3步直接出能交的会议纪要。 很多人找离线会议纪要软件,核心需求就两个: 不联网:会议录音不能上传云端,怕泄露出纪要:不只是转文字&#xff0c…

阅读更多 →
LazyLayoutAlgorithm 一用就全量创建?HarmonyOS 7 可视区懒加载最容易写错的两个参数 2026/10/2 2:35:03

LazyLayoutAlgorithm 一用就全量创建?HarmonyOS 7 可视区懒加载最容易写错的两个参数

LazyLayoutAlgorithm 一用就全量创建?HarmonyOS 7 可视区懒加载最容易写错的两个参数 列表改成 LazyDynamicLayout 后,首屏仍然创建了几百个卡片,启动时间和内存几乎没变。问题往往不在数据源,而在自定义算法里调用了会展开全部节…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉