
本文介绍一种健壮、无越界风险的算法,用于统计二维0-1数组中所有与至少一个1正交相邻(上/下/左/右)的0元素个数,每个0仅计1次,即使被多个1包围。
本文介绍一种健壮、无越界风险的算法,用于统计二维0-1数组中所有**与至少一个1正交相邻(上/下/左/右)的0元素个数**,每个0仅计1次,即使被多个1包围。
在处理二维二值数组(仅含0和1)时,一个常见但易出错的需求是:找出所有“边界零”——即值为0且其上下左右四个正交方向中至少存在一个1的单元格,并对这类0进行去重计数(即每个满足条件的0只算1次,无论它邻接1的数量是1个还是4个)。这看似简单,但初学者常陷入两个陷阱:一是遍历逻辑导致 ArrayIndexOutOfBoundsException;二是错误地以“1为中心”扩张检查,从而重复统计同一0(如一个0被两个1同时邻接,会被加两次)。
正确的解题思路应以0为中心判断:遍历每个位置,若该位置为0,则检查其四个邻居是否至少有一个为1。这样天然规避重复计数,也使边界处理更清晰。
✅ 核心算法设计(推荐实现)
我们采用双层循环遍历所有单元格,对每个值为0的位置,逐一验证其合法邻居(需确保不越界)中是否存在1。使用布尔标志 isAdjacentToOne 记录当前0是否满足条件,一旦确认即累加并跳出邻居检查(提升效率)。
以下是完整、鲁棒、可直接运行的 Java 实现:
public static int borderZeros(int[][] nums) {
// 边界校验:空数组或单元素数组直接返回0
if (nums == null || nums.length == 0) return 0;
int rows = nums.length;
int cols = nums[0].length;
if (rows == 0 || cols == 0) return 0;
int count = 0;
// 遍历每个单元格
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (nums[r][c] == 0) { // 只对0进行检查
boolean isAdjacentToOne = false;
// 检查上、下、左、右四个方向(顺序无关,可提前终止)
if (r > 0 && nums[r - 1][c] == 1) isAdjacentToOne = true; // 上
else if (r < rows - 1 && nums[r + 1][c] == 1) isAdjacentToOne = true; // 下
else if (c > 0 && nums[r][c - 1] == 1) isAdjacentToOne = true; // 左
else if (c < cols - 1 && nums[r][c + 1] == 1) isAdjacentToOne = true; // 右
if (isAdjacentToOne) count++;
}
}
}
return count;
}? 关键设计亮点:
- ✅ 零越界风险:每个方向访问前均用 if 条件严格校验索引有效性(如 r > 0、c
- ✅ 天然去重:每个0独立判断,满足即计1次,杜绝重复;
- ✅ 早停优化:使用 else if 链,一旦任一方向匹配成功即停止后续检查,减少冗余比较;
- ✅ 全尺寸兼容:支持任意 m × n 数组(包括 1×1, 1×n, m×1 等退化情形)。
? 验证示例结果
对题目所给测试用例:
- nums1(4×8)→ 返回 10
- nums2(6×6)→ 返回 18
可配合如下驱动代码快速验证:
public static void main(String[] args) {
int[][] nums1 = {
{0, 0, 1, 0, 1, 0, 1, 0},
{1, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
};
int[][] nums2 = {
{0, 0, 0, 0, 1, 1},
{0, 1, 0, 0, 1, 0},
{0, 1, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0},
{0, 1, 0, 0, 1, 0},
{0, 0, 0, 0, 1, 1}
};
System.out.println(borderZeros(nums1)); // 输出: 10
System.out.println(borderZeros(nums2)); // 输出: 18
}⚠️ 常见误区提醒
- ❌ 不要以1为中心扩散(如原“dumb code”):会导致同一0被多次计数,且边界检查复杂(需为每个1单独判断4个邻居是否越界);
- ❌ 避免硬编码边界偏移(如 r
- ❌ 勿忽略空数组/单行单列场景:必须前置校验 nums == null || nums.length == 0 || nums[0].length == 0;
- ✅ 推荐使用方向数组优化扩展性(进阶):若未来需支持八邻域(含对角线),可定义 int[][] dirs = {{-1,0},{1,0},{0,-1},{0,1}} 统一处理。
✅ 总结
本算法时间复杂度为 O(m×n),空间复杂度为 O(1),简洁、安全、可读性强,完美契合题目所有约束。其核心思想——“以目标元素(0)为锚点,主动探测邻居状态”——是解决此类邻接计数问题的通用范式,值得初学者深入理解并迁移至图像处理、网格游戏、连通域分析等实际场景。










