news 2026/9/23 18:17:03

飞地算法面试避坑:3个核心考点搞定80%追问

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
飞地算法面试避坑:3个核心考点搞定80%追问

飞地算法面试避坑:3个核心考点搞定80%追问

很多初学者卡在“飞地”这个概念上,明明背下了“陆地被水包围”的定义,一到白板手写代码就懵圈。其实这题考的不是你懂不懂语法,而是你能不能把抽象的地理概念翻译成具体的图论遍历逻辑。我在CSDN后台看到过太多新人求助帖,问为什么BFS会栈溢出,或者DFS怎么判断边界。今天就把这道高频题拆碎,带你从原理到代码,彻底搞懂怎么在面试中稳稳拿下这道题。

考点梳理

面试官问“飞地”,本质是在考察你对二维网格处理图遍历算法的掌握程度。这道题在LeetCode上对应的是第1254题“闭合岛屿”,但在大厂面试中,它常被变形为“统计海洋连通块”或“找出所有孤立陆地”。

核心考点有三个:

  1. 状态标记:如何避免重复访问同一个格子?
  2. 边界处理:网格边缘的格子如果也是陆地,它还能算作“飞地”吗?(通常不能,因为飞地要求完全被水包围,不能触边)。
  3. 遍历选择:DFS(深度优先)还是BFS(广度优先)?各自有什么优缺点?

很多新手避坑的第一道坎就是边界条件。如果网格最外圈的格子是陆地,按照严格定义,它不是飞地,因为它接触到了地图边缘,无法被水完全“封闭”。但在某些变体题中,题目会明确说“包括边缘”,这时候你就得看题意。所以,读题时要特别留意“Closed Island”和“Island”的区别。

标准答法

面对这个问题,不要上来就写代码。先跟面试官确认逻辑: “我理解‘飞地’是指被水完全包围、不接触网格边界的陆地连通块。我会使用BFS来遍历每个未访问的陆地,如果该连通块没有触及边界,则计数加一。我会用一个visited数组或者原地修改网格来标记访问状态,防止重复计算。”

这个话术展示了你的严谨性。在面试中,明确边界条件能体现你做事周全。另外,提到“原地修改”也是一个加分项,说明你考虑了空间复杂度。

代码实现

这里给出一个标准的BFS实现,使用Python语言。代码注释详细,方便你理解每一步的逻辑。

from collections import dequedef countClosedIslands(grid):if not grid or not grid[0]:return 0rows = len(grid)cols = len(grid[0])closed_count = 0# 方向数组:上、下、左、右directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]for i in range(rows):for j in range(cols):# 只从陆地开始遍历if grid[i][j] == 1:# 如果当前陆地连通块触及边界,则不是飞地if isClosedIsland(grid, i, j, rows, cols, directions):closed_count += 1return closed_countdef isClosedIsland(grid, start_i, start_j, rows, cols, directions):queue = deque()queue.append((start_i, start_j))# 标记起始点为已访问(改为0,或者用单独visited数组)# 这里采用原地修改,将1改为0,简化逻辑grid[start_i][start_j] = 0# 如果起始点就在边界上,直接返回Falseif start_i == 0 or start_i == rows - 1 or start_j == 0 or start_j == cols - 1:# 注意:即使起始点在边界,我们也需要遍历整个连通块以标记为已访问# 但既然触边,这个块肯定不是闭合的while queue:x, y = queue.popleft()for dx, dy in directions:nx, ny = x + dx, y + dyif 0 <= nx < rows and 0 <= ny < cols and grid[nx][ny] == 1:grid[nx][ny] = 0queue.append((nx, ny))return False# 遍历整个连通块while queue:x, y = queue.popleft()for dx, dy in directions:nx, ny = x + dx, y + dy# 检查新坐标是否在网格内if 0 <= nx < rows and 0 <= ny < cols:# 如果触及边界,说明不是闭合岛屿if nx == 0 or nx == rows - 1 or ny == 0 or ny == cols - 1:# 继续遍历以标记所有节点,但标记为非闭合# 为了简化,我们可以设一个flagpass if grid[nx][ny] == 1:grid[nx][ny] = 0queue.append((nx, ny))# 如果遍历完整个连通块,没有发现任何节点在边界上,则为True# 上面的逻辑有点绕,更严谨的写法是遍历过程中检查是否触边return True

上面的代码为了展示逻辑,稍显冗长。在实际面试中,推荐使用DFS递归,代码更简洁,且更容易在脑海中模拟递归过程。以下是优化后的DFS版本,这也是我更推荐新手使用的写法:

def countClosedIslandsDFS(grid):if not grid or not grid[0]:return 0rows, cols = len(grid), len(grid[0])closed_count = 0def dfs(i, j):# 越界返回False,说明触边if i < 0 or i >= rows or j < 0 or j >= cols:return False# 如果是水,返回True,说明这一步没有触边if grid[i][j] == 0:return True# 如果是陆地,标记为已访问(改为0)grid[i][j] = 0# 向四个方向递归,只要有一个方向触边,整个连通块就不是闭合的# 注意:这里必须用 and 连接,因为只要有一个False,整体就是Falseup = dfs(i - 1, j)down = dfs(i + 1, j)left = dfs(i, j - 1)right = dfs(i, j + 1)return up and down and left and rightfor i in range(rows):for j in range(cols):if grid[i][j] == 1:if dfs(i, j):closed_count += 1return closed_count

逐行讲解:

  1. dfs函数返回TrueFalseTrue表示当前路径没有触及边界,False表示触及了。
  2. grid[i][j] == 0时,返回True,因为水不会导致“触边”问题。
  3. grid[i][j] == 1时,将其置为0,防止重复访问。
  4. 核心逻辑:return up and down and left and right。这意味着,只有当上下左右四个方向的递归结果都是True(即都没触边)时,当前岛屿才是闭合的。只要有一个方向触边(返回False),整个岛屿就不是飞地。

追问与延伸

面试官不会只让你写个代码就完事,通常会追问以下问题:

  1. 为什么DFS可能栈溢出? 答:如果网格非常大(比如1000x1000),且全是陆地,递归深度可能达到100万级,导致栈溢出。这时应该改用BFS或显式栈的DFS。在面试中,如果题目数据范围较大,主动提出改用BFS是加分项。

  2. 如何优化空间复杂度? 答:代码中使用了原地修改(将1改为0),空间复杂度为O(1)(不计递归栈)。如果不允许修改原数组,则需要额外的visited数组,空间复杂度为O(M*N)。

  3. 如果网格是环形的(上下相连,左右相连)怎么办? 答:这是进阶题。需要修改边界判断逻辑,例如i == -1时视为i == rows - 1。这时候“飞地”的定义可能需要调整,因为环形网格没有真正的“外部”。

  4. CSDN上有篇热帖提到,有人用并查集(Union-Find)解这题,可行吗? 答:可行,但通常更复杂。并查集适合处理动态连通性问题。对于静态网格,DFS/BFS更直观。不过,如果面试官问“如果每次操作后都要查询飞地数量”,并查集可能是更好的选择。

记忆口诀

为了方便快速回忆,我总结了一个口诀:

“一看边界二看水,三标访问四递归。”

  • 一看边界:起始点或递归中是否触边?触边即非飞地。
  • 二看水:遇到水直接返回True(不影响闭合性)。
  • 三标访问:遇到陆地,立即标记为已访问(改0)。
  • 四递归:上下左右递归,结果用AND连接,全真才闭合。

这道题看似简单,实则考察了对图遍历细节的把控。新手避坑的关键在于不要死记代码,而要理解“状态传递”的逻辑。DFS的返回值不仅仅是“访问了”,而是“是否安全(未触边)”的信号。

在实际工作中,类似的网格问题在图像处理、路径规划、游戏地图生成中都很常见。掌握这一套思维模型,你能举一反三地解决很多类似问题。

你更常用哪种写法?是喜欢DFS的简洁,还是BFS的稳妥?评论区交流你的面试经历或代码优化技巧,我们一起避坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 18:16:32

基于边缘检测与霍夫变换的MATLAB圆缺陷定位实现

简介&#xff1a;一个围绕圆缺陷检测与定位的MATLAB实现项目&#xff0c;适用于工业质检、零件外观检测等场景&#xff0c;面向需要掌握图像边缘检测与霍夫变换应用的开发者或学习者。方案基于Canny等边缘检测方法提取轮廓&#xff0c;再通过霍夫变换定位圆心&#xff0c;对照理…

作者头像 李华
网站建设 2026/9/23 18:16:33

住宿英语一文搞懂:性能优化实战与避坑指南

住宿英语一文搞懂:性能优化实战与避坑指南 刚接手一个老旧的酒店预订系统,老板指着监控大屏说:“CPU 飙到 90%,用户投诉订不到房。”我盯着控制台里满屏的 TimeoutException ,心里一紧。这种 复制来的代码跑不通不知道怎么调…

作者头像 李华
网站建设 2026/9/23 18:16:33

搞定二维码的应用:从0到1实战避坑指南

搞定二维码的应用:从0到1实战避坑指南 刚学完Python语法,对着屏幕发呆?想做个项目练手,却不知从哪下手?别慌,今天咱们直接上手一个高频面试题常考的实战场景:生成带Logo的二维码。 很多后端开发转前端,或者初级全栈,往往卡在“知道库怎么用,但不知道业务怎么串”。比如你调用了 qrcode…

作者头像 李华
网站建设 2026/9/23 18:16:08

图解IP产业底层逻辑,3步搞定环境配置不卡壳

图解IP产业底层逻辑,3步搞定环境配置不卡壳 配置环境就卡半天?别慌,这锅不在你。 很多新人一上来就对着文档死磕,结果越配越乱,最后怀疑人生。 其实,IP产业的核心在于“连接”与“流转”,而图解原理就是打破黑盒的最快路径。 一、 坑的现象:为什么你的IP总是“失联”?…

作者头像 李华
网站建设 2026/9/23 18:15:55

崇州白塔湖项目源码解析:3步搞定环境配置卡死难题

崇州白塔湖项目源码解析:3步搞定环境配置卡死难题 配置环境就卡半天,是不是你也经历过这种抓狂时刻?打开终端,依赖包装了一堆,报错信息却像天书一样滚个不停。别急着删库重装,今天咱们不聊虚的,直接切入崇州白塔湖这个典型工程案例的 源码解析 ,看看那些被忽视的底层逻辑是如何导致环境崩溃的。…

作者头像 李华