如何判定2D数组中给定节点是否被单一颜色完全包围,相关算法有哪些
适用算法说明
你要实现的判断逻辑可以直接用**洪水填充(Flood Fill)**算法实现,核心逻辑和你描述的完全一致:从目标节点出发,仅允许移动到非指定边界颜色的格子,只要能走到2D数组的边缘,就说明节点未被包围,反之则说明完全被目标颜色包围。
现有代码问题排查
你写的递归版本思路是对的,不符合预期的问题出在以下几点:
- 全局变量污染:
squaresChecked、squareSurrounded都是全局变量,每次调用checkSurrounded函数前如果没有重置这两个变量的初始值,上一次调用的残留数据会直接干扰本次计算结果,比如上一次调用已经把squareSurrounded改为false,本次调用没有改回true,输出结果肯定错误。 - 缺少起始点合法性判断:如果传入的目标坐标本身就是边界颜色,你的代码会直接返回,此时
squareSurrounded还保持初始的true,逻辑不符合预期。 - 递归栈溢出风险:当2D数组尺寸较大时,递归实现的洪水填充会触发JS调用栈溢出,更稳定的实现是换成迭代版本的广度优先遍历(BFS)。
修复后可直接使用的代码
推荐使用BFS迭代版本,避免递归问题:
const boardSize = 15 // 棋盘初始化,可替换为你自己的2D数组数据 const gameBoard = new Array(boardSize).fill(0).map(() => Array(boardSize).fill('white')) function checkSurrounded(startX, startY, boundaryColor) { // 目标节点本身是边界色,不满足被包围的前提,直接返回false if (gameBoard[startX][startY] === boundaryColor) { return false } // 每次调用生成独立的访问记录,避免全局变量污染 const visited = new Set() // 上下左右四个移动方向 const moveDirs = [[1, 0], [-1, 0], [0, 1], [0, -1]] const queue = [[startX, startY]] visited.add(`${startX} ${startY}`) while (queue.length) { const [x, y] = queue.shift() // 已走到数组边缘,说明未被包围 if (x === 0 || x === boardSize - 1 || y === 0 || y === boardSize - 1) { return false } // 遍历四个方向的相邻节点 for (const [dx, dy] of moveDirs) { const nx = x + dx const ny = y + dy const pointKey = `${nx} ${ny}` // 跳过边界色节点和已访问节点 if (gameBoard[nx][ny] === boundaryColor || visited.has(pointKey)) { continue } visited.add(pointKey) queue.push([nx, ny]) } } // 所有可达节点均未触及数组边缘,说明被完全包围 return true }
示例验证
针对你给出的8*8测试数组,要判断坐标[3][3](索引从0开始)是否被颜色1包围,将boardSize改为8、gameBoard替换为对应的测试数组后,调用checkSurrounded(3, 3, 1)会返回true,符合预期结果。
内容的提问来源于stack exchange,提问作者jamaal
相关产品推荐
相关产品推荐

