题目

给你一个大小为 m x n 的矩阵 mat ,请以对角线遍历的顺序,用一个数组返回这个矩阵中的所有元素。

示例 1: image.png

输入: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.length
n == mat[i].length
1 <= m, n <= 10^4
1 <= m * n <= 10^4
-10^5 <= mat[i] [j] <= 10^5

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/diagonal-traverse
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

顺着遍历的思路进行模拟,使用一个变量记录当前遍历方向,如1表示从下向上遍历(行数-1,列数+1),-1表示从上向下遍历(行数+1,列数-1)。

一开始从(0,0)开始遍历,方向为从下向上,每遍历完一个数就进行「行数-1,列数+1」的操作,直至出界,然后变换方向,同时计算下一次遍历的起点。

对于方向从1变为-1,在矩阵上半部分,方向-1的起点为方向1的起点的「右边」的点;在矩阵下半部分,方向-1的起点为方向1的起点的「下边」的点。

对于方向从-1变为1,在矩阵上半部分,方向1的起点为方向-1的起点的「下边」的点;在矩阵下半部分,方向1的起点为方向-1的起点的「右边」的点。

官解」的思路更好一点,根据横纵坐标之和的奇偶性来判断方向。

代码

  1. class Solution {
  2. public int[] findDiagonalOrder(int[][] mat) {
  3. int m = mat.length;
  4. int n = mat[0].length;
  5. int r = 0;
  6. int c = 0;
  7. int[] ans = new int[m * n];
  8. int k = 0;
  9. int dir = 1;
  10. while (k < m * n) {
  11. if (dir == 1) {
  12. while (r >= 0 && c < n) {
  13. ans[k++] = mat[r--][c++];
  14. }
  15. // 循环结束,r和c出界了,要各自退一步拉回来
  16. r++;
  17. c--;
  18. // 在矩阵上半部分,下一次的起点为当前点「右边」的点
  19. if (c + 1 < n) {
  20. c++;
  21. } else {
  22. // 在矩阵下半部分,下一次的起点为当前点「下边」的点
  23. r++;
  24. }
  25. } else {
  26. while (r < m && c >= 0) {
  27. ans[k++] = mat[r++][c--];
  28. }
  29. r--;
  30. c++;
  31. if (r + 1 < m) {
  32. r++;
  33. } else {
  34. c++;
  35. }
  36. }
  37. dir *= -1;
  38. }
  39. return ans;
  40. }
  41. }