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


题意分析
从矩阵左上角开始,沿右上、左下交替的方向,依次读取每一条斜对角线,返回包含全部元素的一维数组。每个格子恰好输出一次,矩阵不一定是正方形。
与其在每一步处理碰到上、下、左、右边界后的转向,不如先确定当前属于哪条对角线,再按该条线的方向输出。沿这两种斜向移动时,行号加列号始终不变,可以用这个和给对角线编号。
解法:按对角线编号枚举
核心思路
[!blue]
令
d = row + col。同一条对角线上的格子共享这个编号,左上角编号为0,右下角为m + n - 2,所以共有m + n - 1条线。按d递增处理,就按题目要求从左上逐条推进到右下。固定
d后,只要确定行号,列号就由col = d - row唯一确定。行本身要求0 <= row <= m - 1;列必须满足0 <= d - row <= n - 1,等价于d - n + 1 <= row <= d。取两组范围的交集,得到low = max(0, d - n + 1)、high = min(d, m - 1)。偶数编号的对角线从左下向右上走,因此行号从
high递减到low,列号随之递增;奇数编号从右上向左下走,行号从low递增到high。改变的是这条线内部的读取顺序,合法范围始终相同。每个格子都有唯一的行列和,所以不会出现在两条不同对角线中;对每条线枚举全部合法行,又覆盖了线上所有格子。因此按上述编号和方向输出,不会遗漏、重复或越界。单行、单列时,每条线自然只包含一个合法位置,无需额外分支。
解题步骤
- 读取行数
m、列数n,创建长度为m * n的结果数组,写指针idx从0开始。- 枚举对角线编号
d = 0到m + n - 2。- 计算本条线的合法行范围
[low, high]。- 若
d为偶数,行号从大到小枚举;否则从小到大枚举。- 每个位置的列号都取
d - row,将对应元素写入ans[idx]后推进写指针。
代码实现
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++) {
// 由列号等于 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++ {
// 由列号等于 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)$,不计必须返回的结果数组,只使用常数个变量。
关键点总结
[!green]
row + col相同的格子属于同一条对角线。- 合法行范围由行边界和列边界共同推出,列号直接用
d - row计算。- 偶数对角线行号递减,奇数对角线行号递增。
- 按对角线枚举避免维护移动方向和多组拐弯分支,单行、单列也自然成立。
易错点总结
[!yellow]
- 编号多枚举一条:最后一条编号是
m + n - 2,循环上界不包含m + n - 1。- 行下界漏掉
+1:列最大只能是n - 1,对应行至少为d - n + 1。- 奇偶方向写反:偶数编号向右上走,行号递减;奇数编号向左下走,行号递增。
- 把列号当作一维下标换算:这里固定的是行列和,列号应为
d - row,不需要除以行数或列数。- 只使用行边界:合法行必须同时满足列范围,取两组范围交集后才适用于非方阵与单行、单列。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 1424. 对角线遍历 II | 中等 | 同样按行列和确定对角线,原题各行长度不同,不能依赖规则矩形的固定边界。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!