给你一个大小为 n x m
的二维整数矩阵 grid
,其中每个元素的值为 0
、1
或 2
。
V 形对角线段 定义如下:
- 线段从
1
开始。 - 后续元素按照以下无限序列的模式排列:
2, 0, 2, 0, ...
。 - 该线段:
- 起始于某个对角方向(左上到右下、右下到左上、右上到左下或左下到右上)。
- 沿着相同的对角方向继续,保持 序列模式 。
- 在保持 序列模式 的前提下,最多允许 一次顺时针 90 度转向 另一个对角方向。
返回最长的 V 形对角线段 的 长度 。如果不存在有效的线段,则返回 0。
示例 1:
输入: grid = [[2,2,1,2,2],[2,0,2,2,0],[2,0,1,1,0],[1,0,2,2,2],[2,0,0,2,2]]
输出: 5
解释:
最长的 V 形对角线段长度为 5,路径如下:(0,2) → (1,3) → (2,4)
,在 (2,4)
处进行 顺时针 90 度转向 ,继续路径为 (3,3) → (4,2)
。
示例 2:
输入: grid = [[2,2,2,2,2],[2,0,2,2,0],[2,0,1,1,0],[1,0,2,2,2],[2,0,0,2,2]]
输出: 4
解释:
最长的 V 形对角线段长度为 4,路径如下:(2,3) → (3,2)
,在 (3,2)
处进行 顺时针 90 度转向 ,继续路径为 (2,1) → (1,0)
。
示例 3:
输入: grid = [[1,2,2,2,2],[2,2,2,2,0],[2,0,0,0,0],[0,0,2,2,2],[2,0,0,2,0]]
输出: 5
解释:
最长的 V 形对角线段长度为 5,路径如下:(0,0) → (1,1) → (2,2) → (3,3) → (4,4)
。
示例 4:
输入: grid = [[1]]
输出: 1
解释:
最长的 V 形对角线段长度为 1,路径如下:(0,0)
。
提示:
n == grid.length
m == grid[i].length
1 <= n, m <= 500
grid[i][j]
的值为0
、1
或2
。
代码
int lenOfVDiagonal(int** grid, int gridSize, int* gridColSize) {
int n = gridSize, m = gridColSize[0];
if (n == 0 || m == 0) return 0;
// 四个方向向量: (dx, dy)
int dx[4] = {1, 1, -1, -1};
int dy[4] = {1, -1, 1, -1};
// 新方向映射: d0 -> 新方向索引 (顺时针90度)
int next_direction[4] = {1, 3, 0, 2};
// 分配四维数组 len[type][d][i][j]
int ****len = (int****)malloc(3 * sizeof(int***));
for (int t = 0; t < 3; t++) {
len[t] = (int***)malloc(4 * sizeof(int**));
for (int d = 0; d < 4; d++) {
len[t][d] = (int**)malloc(n * sizeof(int*));
for (int i = 0; i < n; i++) {
len[t][d][i] = (int*)malloc(m * sizeof(int));
for (int j = 0; j < m; j++) {
len[t][d][i][j] = 0;
}
}
}
}
// 预处理每个方向、每个类型、每个点的最大长度
for (int d = 0; d < 4; d++) {
// 设置遍历顺序(逆方向)
int start_i, end_i, step_i;
int start_j, end_j, step_j;
if (d == 0) { // (1,1): 从右下到左上
start_i = n-1; end_i = -1; step_i = -1;
start_j = m-1; end_j = -1; step_j = -1;
} else if (d == 1) { // (1,-1): 从左下到右上
start_i = n-1; end_i = -1; step_i = -1;
start_j = 0; end_j = m; step_j = 1;
} else if (d == 2) { // (-1,1): 从右上到左下
start_i = 0; end_i = n; step_i = 1;
start_j = m-1; end_j = -1; step_j = -1;
} else { // (-1,-1): 从左上到右下
start_i = 0; end_i = n; step_i = 1;
start_j = 0; end_j = m; step_j = 1;
}
for (int i = start_i; i != end_i; i += step_i) {
for (int j = start_j; j != end_j; j += step_j) {
for (int t = 0; t < 3; t++) {
if (grid[i][j] != t) {
len[t][d][i][j] = 0; // 类型不匹配
} else {
int ni = i + dx[d];
int nj = j + dy[d];
if (ni >= 0 && ni < n && nj >= 0 && nj < m) {
int next_t;
if (t == 1) next_t = 2;
else if (t == 2) next_t = 0;
else next_t = 2; // t == 0
len[t][d][i][j] = 1 + len[next_t][d][ni][nj];
} else {
len[t][d][i][j] = 1; // 边界点
}
}
}
}
}
}
int max_len = 0;
// 遍历每个起点(值为1)
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] != 1) continue;
for (int d0 = 0; d0 < 4; d0++) {
// 不转向情况
int L0 = len[1][d0][i][j];
if (L0 > max_len) max_len = L0;
// 枚举转向位置(0 到 L0-1)
for (int k = 0; k < L0; k++) {
int i0 = i + k * dx[d0];
int j0 = j + k * dy[d0];
// 计算新方向向量和索引
int dx1 = dy[d0];
int dy1 = -dx[d0];
int d1_index = next_direction[d0]; // 新方向索引
int i1 = i0 + dx1;
int j1 = j0 + dy1;
// 计算转向后第一个点的序列类型
int type_next = ((k + 1) % 2 == 1) ? 2 : 0;
int L1 = 0;
if (i1 >= 0 && i1 < n && j1 >= 0 && j1 < m) {
L1 = len[type_next][d1_index][i1][j1];
}
int total_len = k + 1 + L1; // 总长度 = 第一段(k+1) + 第二段(L1)
if (total_len > max_len) max_len = total_len;
}
}
}
}
// 释放内存
for (int t = 0; t < 3; t++) {
for (int d = 0; d < 4; d++) {
for (int i = 0; i < n; i++) {
free(len[t][d][i]);
}
free(len[t][d]);
}
free(len[t]);
}
free(len);
return max_len;
}