Medium
题目描述
给你一个大小为 m x n 的矩阵 mat,请以对角线遍历的顺序,用一个数组返回这个矩阵中的所有元素。
示例 1:
输入:mat = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,4,7,5,3,6,8,9]
示例 2:
输入:mat = [[1,2],[3,4]]
输出:[1,2,3,4]
提示:
m == mat.lengthn == mat[i].length1 <= m, n <= 10^41 <= m * n <= 10^4-10^5 <= mat[i][j] <= 10^5
解题思路
这道题要求按对角线顺序遍历矩阵。观察遍历规律可以发现:
- 对角线方向交替:奇数对角线向上遍历(右上方向),偶数对角线向下遍历(左下方向)
- 对角线识别:位置
(i,j)所在对角线编号为i+j - 边界处理:当到达矩阵边界时需要调整起始位置
解法一:直接模拟 按照对角线方向移动,遇到边界时改变方向并调整位置。需要处理四种边界情况。
解法二:按对角线分组(推荐)
将所有元素按对角线编号 i+j 分组,然后根据对角线编号的奇偶性决定遍历顺序。偶数对角线正序遍历,奇数对角线逆序遍历。
第二种解法更清晰易懂,避免了复杂的边界判断,代码更简洁。
代码实现
class Solution {
public:
vector<int> findDiagonalOrder(vector<vector<int>>& mat) {
int m = mat.size(), n = mat[0].size();
vector<int> result;
map<int, vector<int>> diagonals;
// 按对角线编号分组
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
diagonals[i + j].push_back(mat[i][j]);
}
}
// 按奇偶性决定遍历顺序
for (auto& [diag, elements] : diagonals) {
if (diag % 2 == 0) {
// 偶数对角线:正序
for (int val : elements) {
result.push_back(val);
}
} else {
// 奇数对角线:逆序
for (int i = elements.size() - 1; i >= 0; i--) {
result.push_back(elements[i]);
}
}
}
return result;
}
};
class Solution:
def findDiagonalOrder(self, mat: List[List[int]]) -> List[int]:
m, n = len(mat), len(mat[0])
diagonals = {}
# 按对角线编号分组
for i in range(m):
for j in range(n):
diag = i + j
if diag not in diagonals:
diagonals[diag] = []
diagonals[diag].append(mat[i][j])
result = []
# 按奇偶性决定遍历顺序
for diag in sorted(diagonals.keys()):
if diag % 2 == 0:
# 偶数对角线:正序
result.extend(diagonals[diag])
else:
# 奇数对角线:逆序
result.extend(diagonals[diag][::-1])
return result
public class Solution {
public int[] FindDiagonalOrder(int[][] mat) {
int m = mat.Length, n = mat[0].Length;
var diagonals = new Dictionary<int, List<int>>();
// 按对角线编号分组
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int diag = i + j;
if (!diagonals.ContainsKey(diag)) {
diagonals[diag] = new List<int>();
}
diagonals[diag].Add(mat[i][j]);
}
}
var result = new List<int>();
// 按奇偶性决定遍历顺序
foreach (var kvp in diagonals.OrderBy(x => x.Key)) {
if (kvp.Key % 2 == 0) {
// 偶数对角线:正序
result.AddRange(kvp.Value);
} else {
// 奇数对角线:逆序
var reversed = new List<int>(kvp.Value);
reversed.Reverse();
result.AddRange(reversed);
}
}
return result.ToArray();
}
}
var findDiagonalOrder = function(mat) {
const m = mat.length;
const n = mat[0].length;
const result = [];
let row = 0, col = 0;
let goingUp = true;
for (let i = 0; i < m * n; i++) {
result.push(mat[row][col]);
if (goingUp) {
if (col === n - 1) {
row++;
goingUp = false;
} else if (row === 0) {
col++;
goingUp = false;
} else {
row--;
col++;
}
} else {
if (row === m - 1) {
col++;
goingUp = true;
} else if (col === 0) {
row++;
goingUp = true;
} else {
row++;
col--;
}
}
}
return result;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(m × n) | 需要遍历矩阵中的每个元素一次 |
| 空间复杂度 | O(m × n) | 需要额外存储空间来分组对角线元素 |
相关题目
- . Decode the Slanted Ciphertext (Medium)