QUESTION
medium
题目描述
给定一个含有 M
x N
个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示
输入:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
输出: [1,2,4,7,5,3,6,8,9]
说明
- 给定矩阵中的元素总数不会超过 100000
SOLUTION
这个问题需要注意边界的控制
方法一(按层访问)
这个方法就很暴力了,直接分两种情况代入
- 先来看看单往右下的对角线访问
//单右往下
vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
vector<int> res;
if(matrix.empty()) return res;
const int m = matrix.size();
const int n = matrix[0].size();
for(int l = 0; l < m + n - 1; l++){
int i = (l < n ? 0 : (l - n + 1));
int j = (l < n ? l : (n - 1));
while(i < m && j >= 0){
res.push_back(matrix[i][j]);
i++;
j--;
}
}
return res;
}
- 同理可以写出单往左上的对角线访问
//单左往上
vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
vector<int> res;
if(matrix.empty()) return res;
const int m = matrix.size();
const int n = matrix[0].size();
for(int l = 0; l < m + n - 1; l++){
int i = (l < m ? l : (m - 1));
int j = (l < m ? 0 : (l - m + 1));
while(i >= 0 && j < n){
res.push_back(matrix[i][j]);
i--;
j++;
}
}
return res;
}
合并一下情况就可以写出如下代码:
vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
vector<int> res;
if(matrix.empty()) return res;
const int m = matrix.size();
const int n = matrix[0].size();
for(int l = 0; l < m + n - 1; l++){
if(l % 2 == 0){ //左往上
int i = (l < m ? l : (m - 1));
int j = (l < m ? 0 : (l - m + 1));
while(i >= 0 && j < n){
res.push_back(matrix[i][j]);
i--;
j++;
}
}
else{
int i = (l < n ? 0 : (l - n + 1));
int j = (l < n ? l : (n - 1));
while(i < m && j >= 0){
res.push_back(matrix[i][j]);
i++;
j--;
}
}
}
return res;
}
这个办法主要是要注意每层索引的起始值以及边界
方法二
看了Leetcode关于本题一些评论发现了如下的解释
利用每层的索引和相等
- 假设矩阵无限大
- 索引和为{偶}数,向上遍历,{横}索引值递减,遍历值依次是(x,0),(x-1,1),(x-2,2),…,(0,x)
- 索引和为{奇}数,向下遍历,{纵}索引值递减,遍历值依次是(0,y),(1,y-1),(2,y-2),…,(y,0)
0: (00)
1: (01)(10)
2: (20)(11)(02)
3: (03)(12)(21)(30)
4: (40)(31)(22)(13)(04)
5: (05)(14)(23)(32)(41)(50)
6: (60)(51)................(06)
按照如上的规律,我们可以写出如下的方法
vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
vector<int> res;
if(matrix.empty()) return res;
const int m = matrix.size(); //行数
const int n = matrix[0].size(); //列数
int i = 0;
int j = 0;
for(int l = 0; l < m*n; l++){
res.push_back(matrix[i][j]);
if((i + j) % 2 == 0){ //左往上遍历
if(j == n - 1){ //列坐标到达右边界
i++; //往下移一格准备右往下遍历
}
else if(i == 0){ //行坐标到顶部了
j++; //往右移一格准备右往下遍历
}
else{ //往右上移动一格
i--;
j++;
}
}
else{ //右往下遍历
if(i == m - 1){
j++;
}
else if(j == 0){
i++;
}
else{
i++;
j--;
}
}
return res;
}
}
这种办法是每一次循环遍历一个,然后切换至下一个位置,主要是要注意边界的转换,同时利用了每层索引和相同的规律,比方法一更加精妙一些