目录
- 题目
- 解法
- 代码说明:
- 输出:
- 如何确定起始点?
- 解释一下max(0,d−m+1)是什么意思?
- 如何遍历对角线?
- .push_back是怎么用的?
题目
给你一个大小为 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]
解法
你可以使用C++来实现对矩阵的对角线遍历,返回所有元素。对角线遍历的顺序可以分为两种情况:
- 从左下到右上(从低到高编号的对角线)。
- 从右上到左下(从高到低编号的对角线)。
以下是实现代码:
#include <iostream>
#include <vector>
using namespace std;
vector<int> findDiagonalOrder(vector<vector<int>>& mat) {
if (mat.empty() || mat[0].empty()) return {};
int m = mat.size();
int n = mat[0].size();
vector<int> result;
bool up = true;
// 总共 m + n - 1 条对角线
for (int d = 0; d < m + n - 1; ++d) {
// 存储当前对角线上的元素
vector<int> temp;
// 确定对角线的起始点
int r = up ? min(d, m - 1) : max(0, d - n + 1);
int c = up ? max(0, d - m + 1) : min(d, n - 1);
// 按照当前遍历方向进行遍历
while (r >= 0 && r < m && c >= 0 && c < n) {
temp.push_back(mat[r][c]);
r += up ? -1 : 1;
c += up ? 1 : -1;
}
// 将当前对角线的元素加入到结果数组中
result.insert(result.end(), temp.begin(), temp.end());
// 切换方向
up = !up;
}
return result;
}
int main() {
vector<vector<int>> mat = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
vector<int> result = findDiagonalOrder(mat);
for (int num : result) {
cout << num << " ";
}
return 0;
}
代码说明:
findDiagonalOrder
函数接受一个矩阵mat
,输出按对角线遍历顺序排列的元素数组。up
变量用于跟踪当前遍历方向(从左下到右上或从右上到左下)。- 外层循环控制遍历的对角线数,总共有
m + n - 1
条对角线。 - 内层循环遍历每一条对角线上的元素,将其存储到
temp
中。如果当前是从左下到右上的遍历方向,需要将temp
反转后再加入到结果中。
输出:
对于输入矩阵:
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
}
程序的输出将是:
1 2 4 7 5 3 6 8 9
这样就实现了对矩阵的对角线遍历。
如何确定起始点?
确定对角线遍历的起始点可以通过当前遍历的对角线编号 ( d ) 来决定。我们需要根据 ( d ) 是较小的还是较大的情况来选择矩阵中的起始行和起始列。下面我通过具体例子来说明如何确定起始点。
矩阵的大小为 ( m = 3 ) 行,( n = 3 ) 列,总共需要遍历的对角线数是 ( m + n - 1 = 5 ) 条。
第 0 条对角线:( d = 0 )
- 方向:从左下到右上(up = true)
- 起始点:
- 行 ( r = \min(d, m-1) = \min(0, 2) = 0 )
- 列 ( c = \max(0, d - m + 1) = \max(0, 0 - 3 + 1) = 0 )
- 遍历顺序:从 ( mat[0][0] ) 开始,即 ( 1 )。
第 1 条对角线:( d = 1 )
- 方向:从右上到左下(up = false)
- 起始点:
- 行 ( r = \max(0, d - n + 1) = \max(0, 1 - 3 + 1) = 0 )
- 列 ( c = \min(d, n-1) = \min(1, 2) = 1 )
- 遍历顺序:从 ( mat[0][1] ) 开始,沿对角线遍历 ( 2, 4 )。
第 2 条对角线:( d = 2 )
- 方向:从左下到右上(up = true)
- 起始点:
- 行 ( r = \min(d, m-1) = \min(2, 2) = 2 )
- 列 ( c = \max(0, d - m + 1) = \max(0, 2 - 3 + 1) = 0 )
- 遍历顺序:从 ( mat[2][0] ) 开始,沿对角线遍历 ( 7, 5, 3 )。
通过这样的规则,可以确定每一条对角线的起始点,并根据遍历方向处理对角线上的元素。
解释一下max(0,d−m+1)是什么意思?
起始点,既然是个点既要有行的位置,也需要列的位置
max(0, d - m + 1) 是确定对角线遍历起始点(列号 c)的关键表达式之一,它用来计算当前对角线的列起始位置。为了更好地理解它的作用,我们可以逐步拆解这个公式,并结合矩阵的形状和遍历情况进行解释。
如何遍历对角线?
先分情况获取起始点,随后按平移方法依次获取对角线上的元素
temp.push_back(mat[r][c]);
r += up ? -1 : 1;
c += up ? 1 : -1;
.push_back是怎么用的?
push_back 是 C++ 中 std::vector 容器的一个成员函数,用来在 vector 的末尾添加一个元素。它是动态数组操作中最常用的函数之一,能够方便地向容器中追加新元素。