这道题目来自华为OD机考双机位C卷,考察的是二维矩阵的模拟与遍历算法。题目描述了一个有趣的"数值同化"现象:在一个由0、1、2组成的矩阵中,值为1的元素会随时间推移同化周围(上下左右)的0元素,而值为2的元素则对这种同化具有免疫力。
关键机制理解:
注意:题目示例的输出部分存在明显错误。根据描述,初始矩阵右下角有4个0未被同化(因为被2阻挡),所以正确结果应该是4而非9。这提醒我们在实际解题时要仔细验证示例。
这是最直观的解决方案,模拟同化过程的自然传播方式:
python复制from collections import deque
def count_non_one(matrix):
if not matrix or not matrix[0]:
return 0
m, n = len(matrix), len(matrix[0])
queue = deque()
directions = [(0,1), (1,0), (0,-1), (-1,0)]
# 初始化:找到所有1的位置
for i in range(m):
for j in range(n):
if matrix[i][j] == 1:
queue.append((i, j))
# 特殊处理:题目说明已将(0,0)设为1
if matrix[0][0] != 1:
matrix[0][0] = 1
queue.append((0, 0))
while queue:
x, y = queue.popleft()
for dx, dy in directions:
nx, ny = x + dx, y + dy
if 0 <= nx < m and 0 <= ny < n and matrix[nx][ny] == 0:
matrix[nx][ny] = 1
queue.append((nx, ny))
return sum(1 for row in matrix for cell in row if cell != 1)
时间复杂度分析:
当初始有多个1时(虽然题目限定从(0,0)开始),可以使用层级标记来优化:
java复制import java.util.LinkedList;
import java.util.Queue;
public class Solution {
public int countNonOne(int[][] grid) {
if (grid == null || grid.length == 0) return 0;
int m = grid.length, n = grid[0].length;
Queue<int[]> queue = new LinkedList<>();
int[][] dirs = {{0,1}, {1,0}, {0,-1}, {-1,0}};
// 初始化队列
if (grid[0][0] != 1) {
grid[0][0] = 1;
queue.offer(new int[]{0, 0});
}
while (!queue.isEmpty()) {
int[] cell = queue.poll();
for (int[] dir : dirs) {
int x = cell[0] + dir[0];
int y = cell[1] + dir[1];
if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 0) {
grid[x][y] = 1;
queue.offer(new int[]{x, y});
}
}
}
int count = 0;
for (int[] row : grid) {
for (int num : row) {
if (num != 1) count++;
}
}
return count;
}
}
实际编码时需要特别注意:
javascript复制function countNonOne(matrix) {
if (!matrix || !matrix.length) return 0;
const m = matrix.length, n = matrix[0].length;
const queue = [];
const dirs = [[0,1], [1,0], [0,-1], [-1,0]];
// 初始化队列
if (matrix[0][0] !== 1) {
matrix[0][0] = 1;
queue.push([0, 0]);
}
while (queue.length) {
const [x, y] = queue.shift();
for (const [dx, dy] of dirs) {
const nx = x + dx, ny = y + dy;
if (nx >= 0 && nx < m && ny >= 0 && ny < n && matrix[nx][ny] === 0) {
matrix[nx][ny] = 1;
queue.push([nx, ny]);
}
}
}
return matrix.flat().filter(num => num !== 1).length;
}
cpp复制#include <vector>
#include <queue>
using namespace std;
int countNonOne(vector<vector<int>>& grid) {
if (grid.empty() || grid[0].empty()) return 0;
int m = grid.size(), n = grid[0].size();
queue<pair<int, int>> q;
vector<pair<int, int>> dirs = {{0,1}, {1,0}, {0,-1}, {-1,0}};
if (grid[0][0] != 1) {
grid[0][0] = 1;
q.push({0, 0});
}
while (!q.empty()) {
auto [x, y] = q.front();
q.pop();
for (auto [dx, dy] : dirs) {
int nx = x + dx, ny = y + dy;
if (nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] == 0) {
grid[nx][ny] = 1;
q.push({nx, ny});
}
}
}
int count = 0;
for (auto& row : grid) {
for (int num : row) {
if (num != 1) count++;
}
}
return count;
}
c复制#include <stdlib.h>
#include <stdio.h>
typedef struct {
int x;
int y;
} Point;
int countNonOne(int** grid, int gridSize, int* gridColSize) {
if (gridSize == 0 || gridColSize[0] == 0) return 0;
int m = gridSize, n = gridColSize[0];
Point* queue = malloc(m * n * sizeof(Point));
int front = 0, rear = 0;
int dirs[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}};
if (grid[0][0] != 1) {
grid[0][0] = 1;
queue[rear++] = (Point){0, 0};
}
while (front < rear) {
Point p = queue[front++];
for (int i = 0; i < 4; i++) {
int nx = p.x + dirs[i][0];
int ny = p.y + dirs[i][1];
if (nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] == 0) {
grid[nx][ny] = 1;
queue[rear++] = (Point){nx, ny};
}
}
}
free(queue);
int count = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] != 1) count++;
}
}
return count;
}
| 测试用例描述 | 输入矩阵 | 预期输出 | 验证要点 |
|---|---|---|---|
| 空矩阵 | [] | 0 | 边界条件处理 |
| 全0矩阵 | [[0,0],[0,0]] | 0 | 完全同化情况 |
| 全2矩阵 | [[2,2],[2,2]] | 4 | 完全免疫情况 |
| 示例情况 | [[0,0,0,0],[0,2,2,2],[0,2,0,0],[0,2,0,0]] | 4 | 标准场景验证 |
| 长条形矩阵 | [[0,2,0,2,0]] | 3 | 非方形矩阵处理 |
优化后的Python示例:
python复制def count_non_one_optimized(matrix):
if not matrix or not matrix[0]:
return 0
m, n = len(matrix), len(matrix[0])
queue = []
dirs = [(0,1), (1,0), (0,-1), (-1,0)]
count = sum(1 for row in matrix for cell in row if cell != 1)
if matrix[0][0] != 1:
if matrix[0][0] == 0:
count -= 1
matrix[0][0] = 1
queue.append((0, 0))
while queue:
x, y = queue.pop(0)
for dx, dy in dirs:
nx, ny = x + dx, y + dy
if 0 <= nx < m and 0 <= ny < n and matrix[nx][ny] == 0:
matrix[nx][ny] = 1
count -= 1
queue.append((nx, ny))
return count
无限循环:忘记标记已访问的单元格,导致重复处理
边界检查错误:矩阵索引越界
0 <= nx < m and 0 <= ny < n初始条件遗漏:未正确处理(0,0)位置初始化为1的要求
方向数组定义错误:漏掉某些方向或包含对角线
可视化工具:打印每个时间步的矩阵状态
python复制def print_matrix(matrix):
for row in matrix:
print(' '.join(map(str, row)))
print()
单步跟踪:在小矩阵上手动模拟算法执行过程
单元测试:针对各种边界情况编写测试用例
性能分析:使用大矩阵测试执行时间,优化热点代码
虽然这是一个算法题目,但其核心思想可以应用于:
在华为OD的结对编程环境中,这类题目考察的不仅是算法能力,还包括:
我建议在准备这类机考时,不仅要掌握算法本身,还要练习在有限时间内写出健壮、易读的代码,并养成编写测试用例的习惯。在实际考试中,可以先写出基础解法,确保正确性后再考虑优化。