[LeetCode] Diagonal Traverse 对角线遍历
Given a matrix of M x N elements (M rows, N columns), return all elements of the matrix in diagonal order as shown in the below image.
Example:
Input:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
Output: [1,2,4,7,5,3,6,8,9]
Explanation:

Note:
- The total number of elements of the given matrix will not exceed 10,000.
这道题给了我们一个mxn大小的数组,让我们进行对角线遍历,先向右上,然后左下,再右上,以此类推直至遍历完整个数组,题目中的例子和图示也能很好的帮我们理解。由于移动的方向不再是水平或竖直方向,而是对角线方向,那么每移动一次,横纵坐标都要变化,向右上移动的话要坐标加上[-1, 1],向左下移动的话要坐标加上[1, -1],那么难点在于我们如何处理越界情况,越界后遍历的方向怎么变换。向右上和左下两个对角线方向遍历的时候都会有越界的可能,但是除了左下角和右上角的位置越界需要改变两个坐标之外,其余的越界只需要改变一个。那么我们就先判断要同时改变两个坐标的越界情况,即在右上角和左下角的位置。如果在右上角位置还要往右上走时,那么要移动到它下面的位置的,那么如果col超过了n-1的范围,那么col重置为n-1,并且row自增2,然后改变遍历的方向。同理如果row超过了m-1的范围,那么row重置为m-1,并且col自增2,然后改变遍历的方向。然后我们再来判断一般的越界情况,如果row小于0,那么row重置0,然后改变遍历的方向。同理如果col小于0,那么col重置0,然后改变遍历的方向。参见代码如下:
解法一:
class Solution {
public:
    vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
        if (matrix.empty() || matrix[].empty()) return {};
        int m = matrix.size(), n = matrix[].size(), r = , c = , k = ;
        vector<int> res(m * n);
        vector<vector<int>> dirs{{-,}, {,-}};
        for (int i = ; i < m * n; ++i) {
            res[i] = matrix[r][c];
            r += dirs[k][];
            c += dirs[k][];
            if (r >= m) {r = m - ; c += ; k =  - k;}
            if (c >= n) {c = n - ; r += ; k =  - k;}
            if (r < ) {r = ; k =  - k;}
            if (c < ) {c = ; k =  - k;}
        }
        return res;
    }
};
下面这种方法跟上面的方法思路相同,不过写法有些不同,这里根据横纵左边之和的奇偶性来判断遍历的方向,然后对于越界情况再单独处理即可,参见代码如下:
解法二:
class Solution {
public:
    vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
        if (matrix.empty() || matrix[].empty()) return {};
        int m = matrix.size(), n = matrix[].size(), r = , c = ;
        vector<int> res(m * n);
        for (int i = ; i < m * n; ++i) {
            res[i] = matrix[r][c];
            if ((r + c) %  == ) {
                if (c == n - ) {++r;}
                else if (r == ) {++c;}
                else {--r; ++c;}
            } else {
                if (r == m - ) {++c;}
                else if (c == ) {++r;}
                else {++r; --c;}
            }
        }
        return res;
    }
};
下面这种方法是按遍历方向来按规律往结果res中添加数字的,比如题目中的那个例子,那么添加的顺序如下:
[0,0] -> [0,1],[1,0] -> [2,0],[1,1],[0,2] -> [1,2],[2,1] -> [2,2]
根据遍历的方向不同共分为五层,关键就是确定每一层的坐标范围,其中下边界low = max(0, i - n + 1),这样可以保证下边界不会小于0,而上边界high = min(i, m - 1),这样也保证了上边界不会大于m-1,如果是偶数层,则从上边界往下边界遍历,反之如果是奇数层,则从下边界往上边界遍历,注意从matrix中取数字的坐标,,参见代码如下:
解法三:
class Solution {
public:
    vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
        if (matrix.empty() || matrix[].empty()) return {};
        int m = matrix.size(), n = matrix[].size(), k = ;
        vector<int> res(m * n);
        for (int i = ; i < m + n - ; ++i) {
            int low = max(, i - n + ), high = min(i, m - );
            if (i %  == ) {
                for (int j = high; j >= low; --j) {
                    res[k++] = matrix[j][i - j];
                }
            } else {
                for (int j = low; j <= high; ++j) {
                    res[k++] = matrix[j][i - j];
                }
            }
        }
        return res;
    }
};
下面这种方法就有一点暴力搜索的感觉,不像上面一种精确计算每一层的坐标范围,这种方法是利用对角线上的数字的横纵坐标之和恒定这一特性来搜索的,然后把和为特定值的数字加入结果res中,参见代码如下:
解法四:
class Solution {
public:
    vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
        if (matrix.empty() || matrix[].empty()) return {};
        int m = matrix.size(), n = matrix[].size(), k = ;
        vector<int> res;
        for (int k = ; k < m + n - ; ++k) {
            int delta =  -  * (k %  == );
            int ii = (m - ) * (k %  == );
            int jj = (n - ) * (k %  == );
            for (int i = ii; i >=  && i < m; i += delta) {
                for (int j = jj; j >=  && j < n; j += delta) {
                    if (i + j == k) {
                        res.push_back(matrix[i][j]);
                    }
                }
            }
        }
        return res;
    }
};
参考资料:
https://discuss.leetcode.com/topic/77866/short-bf-solution
https://discuss.leetcode.com/topic/77865/concise-java-solution/2
https://discuss.leetcode.com/topic/77862/my-8ms-short-solution-9line
https://discuss.leetcode.com/topic/77937/java-15-lines-without-using-boolean
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Diagonal Traverse 对角线遍历的更多相关文章
- 498 Diagonal Traverse 对角线遍历
		详见:https://leetcode.com/problems/diagonal-traverse/description/ C++: class Solution { public: vector ... 
- Leetcode 498:对角线遍历Diagonal Traverse(python3、java)
		对角线遍历 给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示. Given a matrix of M x N elemen ... 
- 498. Diagonal Traverse对角线z型traverse
		[抄题]: Given a matrix of M x N elements (M rows, N columns), return all elements of the matrix in dia ... 
- [Swift]LeetCode498. 对角线遍历 | Diagonal Traverse
		Given a matrix of M x N elements (M rows, N columns), return all elements of the matrix in diagonal ... 
- 【LeetCode】498. Diagonal Traverse 解题报告(Python)
		[LeetCode]498. Diagonal Traverse 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: htt ... 
- LeetCode:对角线遍历【498】
		LeetCode:对角线遍历[498] 题目描述 给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示. 示例: 输入: [ [ ... 
- Leetcode 498.对角线遍历
		对角线遍历 给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示. 示例: 输入: [ [ 1, 2, 3 ], [ 4, 5, ... 
- 498. (leetcode)对角线遍历
		498. 对角线遍历 根据题目的图像看,主要有两种走法,第一种是向右上(顺时针方向),第二种是向左下(逆时针)走 我们设 x ,y初始为0,分别对应横纵坐标 现在分析右上(0,2) 为例:(注意右上的 ... 
- Java实现 LeetCode 498 对角线遍历
		498. 对角线遍历 给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示. 示例: 输入: [ [ 1, 2, 3 ], [ ... 
随机推荐
- android scrollview 属性
			理论部分1.ScrollView和HorizontalScrollView是为控件或者布局添加滚动条2.上述两个控件只能有一个孩子,但是它并不是传统意义上的容器3.上述两个控件可以互相嵌套4.滚动条 ... 
- PHP 引用是个坑,请慎用
			去年我参加了很多次会议,其中八次会议里我进行了相关发言,这其中我多次谈到了 PHP 的引用问题,因为很多人对它的理解有所偏差.在深入讨论这个问题之前,我们先回顾一下引用的基本概念,明确什么是" ... 
- 第1次作业:这是我的一个响亮的标题X!
			1.我是回答问题的部分 part 1: 从小学开始,我就觉得写作文是一件很痛苦的事情.(痛苦ing) 所以呢,选择工科好像就是理所当然的. 至于为什么选择计算机,主要原因就是不知道应该选什么,正好看到 ... 
- Git简单图文教程
			环境: Windows [版本 10.0.15063]64位 Git-2.14.1 64位[下载] TortoiseGit-2.5.0.0 64位[下载],这是一个Git 客户端,外号"乌龟 ... 
- 2017-2018-1 Java演绎法 第二周 作业
			团队任务:讨论Android上的游戏软件 参考现代软件工程 第一章 [概论]练习与讨论: 软件有很多种,也有各种分类办法,本次团队任务是讨论选取Android上的一个游戏软件,考虑到每位组员接触的游戏 ... 
- iOS开发-即时通信XMPP
			1. 即时通信 1> 概述 即时通讯(Instant Messaging)是目前Internet上最为流行的通讯方式,各种各样的即时通讯软件也层出不穷,服务提供商也提供了越来越丰富的通讯服务功能 ... 
- *.db-journal 是什么(android sqlite )数据库删除缓存
			sqlite的官方文档,发现该文件是sqlite的一个临时的日志文件,主要用于sqlite数据库的事务回滚操作了.在事务开始时产生,在事务操作完毕时自动删除,当程序发生崩溃或一些意外情况让程序非法结束 ... 
- 构建微服务开发环境4————安装Docker及下载常用镜像
			[内容指引] 下载Docker: Mac下安装Docker: Windows下安装Docker; 下载常用docker镜像. 一.下载Docker 1.Mac适用Docker下载地址:https:// ... 
- Scala 对象
			1. 单例对象 对于任何你在Java中会使用单例对象的地方, 在scala中都可以使用对象来实现; scala字段没有静态方法或者静态字段, 可以使用object语法结构达到同样的效果,对象(obje ... 
- 不看就亏了:DELL EqualLogic PS6100详解及数据恢办法
			DELL EqualLogic PS6100采用虚拟ISCSI SAN阵列,为远程或分支办公室.部门和中小企业存储部署带来企业级功能.智能化.自动化和可靠性,支持VMware.Solaris.Linu ... 
