leetcode-对角线遍历

86 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情

题目描述

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

示例 1:

示例1.jpg

输入: 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 <= 104
  • 1 <= m * n <= 104
  • -105 <= mat[i][j] <= 105

思路

首先我们可以想一下怎么遍历所有的对角线,可以分成2类:

  • 起点在最左侧这一列
  • 起点在最下面这一行 无论m和n哪个大,都可以分成上述2类,如下图所示

498-1.png

所以,我们通过遍历这个L行的边缘,就可以遍历这个矩形所有的对角线。
接下来我们想一下怎么遍历每条对角线内部的点。其实不难发现,在1条对角线上,相邻2个点始终满足

x2 = x1 - 1
y2 = y1 + 1

我们找到了起点之后,就可以使用这种方式去遍历对角线内部的点,直到x或者y超过矩形的范围。
当然,本题还有一个注意点是,对角线的顺序是按照一正一反类似斑马线交替的,所以我们可以使用一个变量reverse来保存当前的顺序,遍历下1条对角线的时候进行取反就好。

Java版本代码

class Solution {
    public int[] findDiagonalOrder(int[][] mat) {
        int m = mat.length;
        int n = mat[0].length;
        int[] arr = new int[m * n];
        int index = 0;
        // 是否需要反向的标识
        boolean reverse = false;
        // 起点在最左侧的对角线
        for (int k = 0; k < m; k++) {
            int x = k, y = 0;
            List<Integer> line = new ArrayList<>();
            while (x >= 0 && x < m && y >= 0 && y < n) {
                line.add(mat[x--][y++]);
            }
            // 反向
            if (reverse) {
                Collections.reverse(line);
            }
            // 交替,1条正向,1条反向
            reverse = !reverse;
            for (int item : line) {
                arr[index++] = item;
            }
        }
        // 起点在最下方的对角线
        for (int k = 1; k < n; k++) {
            int x = m - 1, y = k;
            List<Integer> line = new ArrayList<>();
            while (x >= 0 && x < m && y >= 0 && y < n) {
                line.add(mat[x--][y++]);
            }
            // 反向
            if (reverse) {
                Collections.reverse(line);
            }
            // 交替,1条正向,1条反向
            reverse = !reverse;
            for (int item : line) {
                arr[index++] = item;
            }
        }
        return arr;
    }
}