LeetCode 498. 对角线遍历
题目描述

题意分析
给定一个 $m \times n$ 的矩阵,要求把全部元素按「对角线蛇形」的次序装进一个一维数组返回:先沿一条斜线从左下往右上走完,再沿下一条斜线从右上往左下走回来,如此反复,直到所有格子都被访问过一次。
题目给出的约束里有两个明确信号。其一,输出长度恰好是 $m \cdot n$,说明每个元素不多不少访问一次,不存在跳过或重复,这就把「循环要跑多少次」这个问题提前定死了。其二,$m$ 和 $n$ 都可以低到 1,也就是说单行矩阵和单列矩阵都是合法输入,而这两种形状恰好会让「拐弯」发生在每一步,是最容易写挂的输入。
需要留意的边界还有一个:题目只要求返回顺序,没有额外的空间限制,因此结果数组本身不算进额外开销,真正要控制的是除结果之外还用了多少变量。
另外注意输出次序是从矩阵左上角
mat[0][0]出发的,第一条斜线只有它一个元素,所以起手方向必须是「往右上」,否则整个序列就反了。
解法:按方向模拟对角线行走
核心思路
问题关键:同一条对角线上的坐标都满足
row + col = d,对角线编号d从 0 到m + n - 2。题目要求的蛇形顺序,本质上只是相邻对角线采用相反的遍历方向。为什么按对角线编号枚举:逐格移动需要处理上、下、左、右四种碰壁情况;直接固定
\[low=\max(0,d-n+1), \quad high=\min(d,m-1)\]d后,只需确定这一条线合法的行范围:列号始终由
col = d - row得到。d为偶数时,从high到low枚举行,方向是右上;d为奇数时,从low到high枚举行,方向是左下。不变量与正确性:开始处理第
d条对角线时,所有坐标和小于d的格子已经按要求写入。区间[low, high]恰好包含所有满足row + col = d的合法行,每行又唯一对应一列,因此本轮不重不漏;奇偶性决定的方向与题目要求一致。处理完最后一个d后,矩阵的每个格子恰好输出一次。
解题步骤
- 创建长度为
m * n的结果数组,并维护写入位置idx。- 枚举对角线编号
d = 0 ... m+n-2。- 计算本条对角线的合法行区间
[low, high]。d为偶数时行号递减,为奇数时行号递增;列号统一取d - row。- 全部对角线处理完后返回结果。
对
[[1,2,3],[4,5,6],[7,8,9]],各条对角线依次输出[1]、[2,4]、[7,5,3]、[6,8]、[9],合并后得到[1,2,4,7,5,3,6,8,9]。
代码实现
class Solution {
public int[] findDiagonalOrder(int[][] mat) {
int m = mat.length;
int n = mat[0].length;
int[] ans = new int[m * n];
int idx = 0;
for (int d = 0; d < m + n - 1; d++) {
int low = Math.max(0, d - n + 1);
int high = Math.min(d, m - 1);
if ((d & 1) == 0) {
for (int row = high; row >= low; row--) {
ans[idx++] = mat[row][d - row];
}
} else {
for (int row = low; row <= high; row++) {
ans[idx++] = mat[row][d - row];
}
}
}
return ans;
}
}
func findDiagonalOrder(mat [][]int) []int {
m, n := len(mat), len(mat[0])
ans := make([]int, m*n)
idx := 0
for d := 0; d < m+n-1; d++ {
low := max(0, d-n+1)
high := min(d, m-1)
if d%2 == 0 {
for row := high; row >= low; row-- {
ans[idx] = mat[row][d-row]
idx++
}
} else {
for row := low; row <= high; row++ {
ans[idx] = mat[row][d-row]
idx++
}
}
}
return ans
}
复杂度分析
- 时间复杂度:$O(mn)$,每个格子恰好写入一次。
- 空间复杂度:$O(1)$,不计必须返回的结果数组,只使用常数个变量。
关键点总结
row + col相同的格子属于同一条对角线。- 合法行范围由行边界和列边界共同推出,列号直接用
d - row计算。- 偶数对角线行号递减,奇数对角线行号递增。
- 按对角线枚举避免维护移动方向和多组拐弯分支,单行、单列也自然成立。
易错点总结
- 对角线数量写成
m + n:会多处理一条空对角线;正确数量是m + n - 1。- 行范围少了
+1:low应为d - n + 1,否则col = d-row可能等于n而越界。- 奇偶方向写反:起点
(0,0)所在的第 0 条对角线按右上方向,因此偶数对角线必须让行号递减。- 列号除以行数或列数:本解法不是一维展开,列号始终是
d - row。- 只按方阵验证:
1 \times n、m \times 1和非方阵更容易暴露边界公式错误。
相似题目
| 题目 | 难度 | 考察点 |
|---|---|---|
| 1424. 对角线遍历 II | 中等 | 锯齿数组下改用 i + j 分桶,方向模拟失效 |
| 54. 螺旋矩阵 | 中等 | 四边界收缩式模拟,拐弯靠边界内移而非奇偶翻转 |
| 59. 螺旋矩阵 II | 中等 | 同样的螺旋次序反过来用于填值而非读值 |
| 48. 旋转图像 | 中等 | 原地坐标映射,考察四元素轮换而非顺序遍历 |
| 867. 转置矩阵 | 简单 | 最简单的下标互换,作为坐标变换类的入门对照 |
| 566. 重塑矩阵 | 简单 | 一维下标与二维坐标的相互换算 |
| 73. 矩阵置零 | 中等 | 用首行首列当标记位,考察 $O(1)$ 额外空间的技巧 |