
本文介绍一种鲁棒、无越界风险的算法,用于统计二维二进制数组中至少与一个1正交相邻(上/下/左/右)的0元素个数,每个0仅计一次,即使被多个1包围。
本文介绍一种鲁棒、无越界风险的算法,用于统计二维二进制数组中**至少与一个1正交相邻(上/下/左/右)的0元素个数**,每个0仅计一次,即使被多个1包围。
在处理二维二进制数组的邻域分析任务时,一个常见但易错的需求是:找出所有“被1包围”的0——即该0的上下左右四个正交方向中至少存在一个1;同时要求每个这样的0只计数一次(去重),无论它毗邻1的数量是1个还是4个。初学者常采用“遍历1、检查其邻居”的思路,却极易因边界判断疏漏引发 ArrayIndexOutOfBoundsException,或因重复计数导致结果偏高。
正确的解题策略应以0为观察主体,逐个检查每个0是否满足“邻接1”的条件。这种方法天然规避越界风险(只需对每个0的四个方向做安全索引校验),且天然保证每个0仅被判定一次,完美契合“不重复计数”的核心要求。
以下是完整、健壮、可直接运行的 Java 实现:
public static int borderZeros(int[][] nums) {
// 边界情况:空数组或单元素数组
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++) {
// 只关注值为0的单元格
if (nums[r][c] == 0) {
boolean adjacentToOne = false;
// 检查上、下、左、右四个方向(正交邻接)
// 上
if (r > 0 && nums[r - 1][c] == 1) adjacentToOne = true;
// 下
if (r < rows - 1 && nums[r + 1][c] == 1) adjacentToOne = true;
// 左
if (c > 0 && nums[r][c - 1] == 1) adjacentToOne = true;
// 右
if (c < cols - 1 && nums[r][c + 1] == 1) adjacentToOne = true;
if (adjacentToOne) {
count++;
}
}
}
}
return count;
}✅ 算法优势说明:
- 安全无异常:所有方向访问前均进行 r > 0、r
- 天然去重:每个0仅被访问一次,并在首次确认其邻接1后立即计数,不存在重复累加逻辑;
- 时间复杂度最优:O(m×n),需遍历全部单元格,不可进一步降低;
- 空间复杂度最优:O(1),仅使用常量额外空间。
⚠️ 注意事项:
- 该算法严格遵循题目定义:仅考虑正交(四连通)邻接,不包含对角线方向;
- 输入数组允许不规则(每行长度不同),代码中通过 nums[r].length 动态获取列数,增强鲁棒性;
- 若需扩展为支持八连通(含对角线),仅需增加4个方向判断,但本题明确排除该情形。
验证示例:
- nums1 返回 10,nums2 返回 18,与预期完全一致。
- 即使输入为 {{0}}、{{1}} 或 null,函数也安全返回 0。
总结而言,本方案摒弃了“从1出发扩散”的易错路径,转而采用“以0为中心、主动探测邻域”的清晰范式。它不仅正确、高效、易理解,更体现了算法设计中“问题建模优先于技巧堆砌”的工程思维——对初学者而言,这是比图论匹配等高级抽象更坚实、更实用的第一课。










