华为OD机试中的“机器人活动区域”题目是一个典型的图论和搜索算法问题,要求在一个二维网格中找出满足特定条件的连续区域,并计算这些区域中最大的一个区域所包含的格子数。具体来说,这个问题要求机器人能够在网格中移动,其移动规则是相邻格子之间的数字编号差值的绝对值必须小于等于1。
题目描述
- 输入:
- 第一行包含两个整数M和N,分别表示网格的行数和列数。
- 接下来的M行,每行包含N个整数,表示网格中每个格子的数字编号。
- 输出:
- 输出一个整数,表示机器人可活动的最大范围对应的网格点数目。
解题思路
- 遍历网格:从网格的左上角开始,逐个遍历每个格子。
- 深度优先搜索(DFS)或广度优先搜索(BFS):
- 当遍历到一个格子时,检查其所有相邻的格子(上、下、左、右四个方向,也可以考虑对角线方向,但题目通常只要求四个基本方向)。
- 如果相邻格子的数字编号与当前格子满足差值绝对值小于等于1的条件,则将该相邻格子加入到当前区域中,并继续对该相邻格子进行相同的搜索过程。
- 使用一个标记数组来记录哪些格子已经被访问过,以避免重复访问。
- 计算区域大小:在搜索过程中,统计当前区域包含的格子数。
- 寻找最大区域:遍历完整个网格后,找到并输出所有区域中最大的一个区域所包含的格子数。
示例
示例1
- 输入:
4 4 1 2 5 2 2 4 4 5 3 5 7 1
- 输出:
解释:在这个网格中,存在一个由6个格子组成的最大区域,这些格子的数字编号满足相邻格子之间差值的绝对值小于等于1的条件。6
示例2
- 输入:
2 3 1 3 5 4 1 3
- 输出:
解释:在这个网格中,任意两个相邻格子之间的差值绝对值都大于1,因此机器人无法在不同格子之间移动,只能在单个格子内活动。1
注意事项
- 在编写代码时,要注意边界条件的处理,确保不会越界访问网格。
- 使用标记数组来避免重复访问已经访问过的格子。
- 在搜索过程中,要及时更新当前区域的大小,并在遍历完整个网格后找到并输出最大的区域大小。
当然,下面我将给出解决“机器人活动区域”问题的详细解题步骤,这个问题通常涉及到图的遍历算法,如深度优先搜索(DFS)或广度优先搜索(BFS)。为了简化,我们将使用DFS作为遍历方法。
解题步骤
1. 初始化
- 输入处理:读取网格的行数
M
和列数N
,以及网格中每个格子的数字编号。 - 创建网格:根据输入数据,创建一个二维数组
grid
来存储网格,其中grid[i][j]
表示第i
行第j
列的格子编号。 - 创建访问标记数组:创建一个同样大小的二维布尔数组
visited
,用于标记网格中的格子是否已被访问过。初始时,所有格子都未被访问(即visited[i][j] = false
)。
2. 深度优先搜索(DFS)
- 定义DFS函数:该函数接受当前格子的行索引
row
、列索引col
以及当前区域的大小size
作为参数。 - 边界检查:在尝试访问相邻格子之前,检查当前格子的行索引和列索引是否在网格范围内内(即
0 <= row < M
和0 <= col < N
)。 - 访问标记:将当前格子标记为已访问(即
visited[row][col] = true
)。 - 递归搜索:对于当前格子的每个相邻格子(上、下、左、右),如果它未被访问过(即
!visited[newRow][newCol]
)且满足差值条件(即|grid[newRow][newCol] - grid[row][col]| <= 1
),则递归调用DFS函数,并将相邻格子的行索引、列索引以及当前区域大小加1作为参数传递。 - 更新区域大小:在DFS过程中,通过递归调用时的参数传递,不断更新当前区域的大小。
3. 遍历网格并应用DFS
- 遍历网格中的每个格子。
- 对于每个未访问过的格子(即
!visited[i][j]
),调用DFS函数,以该格子为起点开始搜索,并将初始区域大小设置为1。 - 在每次DFS调用后,检查并更新找到的最大区域大小。
4. 输出结果
- 遍历完整个网格后,输出找到的最大区域大小。
示例代码(Java)
public class RobotActivityArea {
private static final int[][] DIRECTIONS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 上下左右
/**
* 计算二维网格中最大的岛屿面积
* 岛屿由1表示,水域由0表示,岛屿的定义是水平或垂直连接的1的集合
* 此函数通过深度优先搜索(DFS)算法来遍历每个网格,找出最大的岛屿面积
*
* @param grid 二维网格,由0和1组成,0代表水域,1代表岛屿的一部分
* @return 返回最大岛屿的面积如果网格为空或没有岛屿,则返回0
*/
public static int maxArea(int[][] grid) {
// 检查网格是否为空或者没有岛屿,如果是,则直接返回0
if (grid == null || grid.length == 0 || grid[0].length == 0) {
return 0;
}
// 初始化网格的行数和列数
int rows = grid.length;
int cols = grid[0].length;
// 创建一个二维布尔数组,用于记录每个网格是否已经被访问过
boolean[][] visited = new boolean[rows][cols];
// 初始化最大岛屿面积为0
int maxArea = 0;
// 遍历每个网格
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
// 如果当前网格没有被访问过,则计算从这个网格出发的岛屿面积
if (!visited[i][j]) {
int currentArea = dfs(grid, visited, i, j);
// 更新最大岛屿面积
maxArea = Math.max(maxArea, currentArea);
}
}
}
// 返回最大岛屿面积
return maxArea;
}
/**
* 深度优先搜索计算网格区域
*
* @param grid 二维网格数组,表示地图
* @param visited 二维布尔数组,表示是否访问过
* @param row 当前行位置
* @param col 当前列位置
* @return 返回从给定位置开始的网格区域大小
*/
private static int dfs(int[][] grid, boolean[][] visited, int row, int col) {
// 检查grid和visited是否为空或null
if (grid == null || grid.length == 0 || visited == null || visited.length == 0) {
return 0;
}
// 获取网格的行数和列数
int rows = grid.length;
int cols = grid[0].length;
// 检查当前位置是否越界或已被访问,如果是,则返回0
if (row < 0 || row >= rows || col < 0 || col >= cols || visited[row][col]) {
return 0;
}
// 将当前位置标记为已访问
visited[row][col] = true;
// 初始化区域计数为1,代表当前位置
int area = 1;
// 遍历四个方向(假设DIRECTIONS已定义为包含四个方向的数组:{-1, 0}, {1, 0}, {0, -1}, {0, 1})
for (int[] direction : DIRECTIONS) {
// 计算下一个位置的行和列
int newRow = row + direction[0];
int newCol = col + direction[1];
// 如果下一个位置有效,则累加其区域
if (isValid(grid, visited, newRow, newCol, grid[row][col])) {
area += dfs(grid, visited, newRow, newCol);
}
}
// 返回当前位置开始的区域大小
return area;
}
// 假设isValid方法已定义,用于检查给定位置是否为有效位置
// 返回true如果位置有效,否则返回false
private static boolean isValid(int[][] grid, boolean[][] visited, int row, int col, int prevValue) {
// 检查位置是否越界和已被访问
// 检查当前位置的值是否与前一个位置的值相同(这里假设我们只关心连续相同的值)
// 根据实际情况可能需要更复杂的逻辑来判断有效性
return row >= 0 && row < grid.length && col >= 0 && col < grid[0].length && !visited[row][col] && grid[row][col] == prevValue;
}
public static void main(String[] args) {
int[][] grid = {
{1, 2, 5, 2},
{2, 4, 4, 5},
{3, 5, 7, 1}
};
System.out.println("Max area: " + maxArea(grid));
}
}