leetcode
leetcode 451 ~ 500
对角线遍历

对角线遍历

难度:

标签:

题目描述

给你一个大小为 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]

 

提示:

  • m == mat.length
  • n == mat[i].length
  • 1 <= m, n <= 104
  • 1 <= m * n <= 104
  • -105 <= mat[i][j] <= 105

代码结果

运行时间: 54 ms, 内存: 18.7 MB


/*
 * 思路:
 * 使用Java Stream API处理数据。
 * 我们沿着对角线遍历矩阵,交替遍历向上和向下的对角线。
 * 当总和为偶数时,我们向上遍历,当总和为奇数时,我们向下遍历。
 * 遍历的过程中,我们将矩阵中的元素加入结果列表中。
 */
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.ArrayList;
import java.util.List;
 
public class DiagonalTraverseStream {
    public int[] findDiagonalOrder(int[][] mat) {
        int m = mat.length;
        int n = mat[0].length;
        List<Integer> result = new ArrayList<>();
        for (int d = 0; d < m + n - 1; d++) {
            final int sum = d;
            List<Integer> diagonal = IntStream.range(0, m)
                    .filter(i -> sum - i >= 0 && sum - i < n)
                    .mapToObj(i -> mat[i][sum - i])
                    .collect(Collectors.toList());
            if (d % 2 == 0) {
                result.addAll(diagonal);
            } else {
                for (int i = diagonal.size() - 1; i >= 0; i--) {
                    result.add(diagonal.get(i));
                }
            }
        }
        return result.stream().mapToInt(i -> i).toArray();
    }
}

解释

方法:

这个题解采用了分组和遍历的策略来实现对角线遍历。首先,根据矩阵元素的坐标(i, j),每个元素被分配到对应的对角线组里,这个组的索引是i+j。这意味着所有在同一个对角线上的元素会被放在同一个列表中。创建了一个列表数组ans来存储这些对角线组。然后,根据对角线的索引顺序,决定了遍历的方向:偶数索引的对角线从上到下遍历(逆序插入到结果列表中),奇数索引的对角线则从下到上遍历(顺序插入)。这样可以确保输出结果符合对角线遍历的要求。

时间复杂度:

O(m*n)

空间复杂度:

O(m*n)

代码细节讲解

🦆
请问在将每个元素按坐标和对角线的关系添加到对应列表时,为何选择了索引`i+j`作为对角线的标识?
在一个矩阵中,每个元素的坐标是(i, j),其中i是行索引,j是列索引。当我们考虑对角线遍历时,可以发现处于同一对角线上的元素满足i+j为常数。例如,从左上角到右下角第一条对角线上的元素坐标为(0,0),第二条为(0,1), (1,0),它们的i+j值分别是0和1。因此,使用i+j作为索引可以自然地将元素按其所在的对角线分组,便于后续的遍历处理。
🦆
在处理对角线元素的遍历方向时,代码中提到偶数索引对角线逆序添加,奇数索引顺序添加,这样的处理是基于什么考虑?
这种处理方式基于对角线遍历的特定要求,即交替改变遍历元素的方向。从矩阵的左上角开始,首先向上遍历,然后改变方向向下遍历,再次改变方向向上遍历,依此类推。在实现中,使用偶数索引(i+j为偶数)的对角线逆序添加模拟了从下到上的遍历效果,而奇数索引的对角线则顺序添加,模拟从上到下的遍历效果。这样可以确保输出的顺序符合题目的对角线遍历要求。
🦆
代码中使用了`ans[i+j].append(mat[i][j])`将元素添加到对应列表,这种添加方式是否考虑了对角线元素在原矩阵中的顺序?
是的,此添加方式考虑了元素在原矩阵中的顺序。由于是按照从左到右,从上到下的顺序遍历矩阵元素,因此在同一对角线(i+j值相同)上的元素会按照它们在原矩阵中出现的顺序被添加到对应的列表中。这确保了在同一对角线内的元素,其相对顺序是根据它们在矩阵中的位置决定的。
🦆
在对ans列表进行遍历时,为什么每个对角线列表都需要分别处理逆序和顺序添加,这种方法相比于直接合并有什么优势?
每个对角线列表分别处理逆序和顺序添加的方式是为了模拟对角线遍历中的方向变换。如果直接合并每个对角线的元素,无法实现所需的上下交替遍历的效果。通过逆序和顺序处理,可以确保对角线遍历的输出顺序符合题目要求,同时也避免了在遍历完成后再进行额外的排序或重排操作,提高了算法的效率。

相关问题