leetcode
leetcode 1101 ~ 1150
将矩阵按对角线排序

将矩阵按对角线排序

难度:

标签:

题目描述

矩阵对角线 是一条从矩阵最上面行或者最左侧列中的某个元素开始的对角线,沿右下方向一直到矩阵末尾的元素。例如,矩阵 mat63 列,从 mat[2][0] 开始的 矩阵对角线 将会经过 mat[2][0]mat[3][1]mat[4][2]

给你一个 m * n 的整数矩阵 mat ,请你将同一条 矩阵对角线 上的元素按升序排序后,返回排好序的矩阵。

 

示例 1:

输入:mat = [[3,3,1,1],[2,2,1,2],[1,1,1,2]]
输出:[[1,1,1,1],[1,2,2,2],[1,2,3,3]]

示例 2:

输入:mat = [[11,25,66,1,69,7],[23,55,17,45,15,52],[75,31,36,44,58,8],[22,27,33,25,68,4],[84,28,14,11,5,50]]
输出:[[5,17,4,1,52,7],[11,11,25,45,8,69],[14,23,25,44,58,15],[22,27,31,36,50,66],[84,28,75,33,55,68]]

 

提示:

  • m == mat.length
  • n == mat[i].length
  • 1 <= m, n <= 100
  • 1 <= mat[i][j] <= 100

代码结果

运行时间: 28 ms, 内存: 16.3 MB


/*
 * 思路:
 * 1. 使用流(Stream)遍历矩阵的每条对角线,记录对角线上的元素。
 * 2. 对对角线上的元素进行排序。
 * 3. 将排序后的元素放回矩阵相应的位置。
 */
import java.util.*;
import java.util.stream.Collectors;

public class Solution {
    public int[][] diagonalSort(int[][] mat) {
        int m = mat.length;
        int n = mat[0].length;
        // 处理左下到右上的对角线
        for (int i = 0; i < m; i++) {
            sortDiagonal(mat, i, 0, m, n);
        }
        // 处理上到右下的对角线
        for (int j = 1; j < n; j++) {
            sortDiagonal(mat, 0, j, m, n);
        }
        return mat;
    }

    private void sortDiagonal(int[][] mat, int row, int col, int m, int n) {
        List<Integer> diagonal = new ArrayList<>();
        int r = row, c = col;
        while (r < m && c < n) {
            diagonal.add(mat[r][c]);
            r++;
            c++;
        }
        diagonal = diagonal.stream().sorted().collect(Collectors.toList());
        r = row;
        c = col;
        int index = 0;
        while (r < m && c < n) {
            mat[r][c] = diagonal.get(index++);
            r++;
            c++;
        }
    }
}

解释

方法:

该题解通过对每个对角线上的元素进行收集、排序和重新放置来解决问题。首先,定义一个辅助函数 helpSort 来处理从特定起点 (startI, startJ) 开始的对角线元素。该函数首先遍历对应的对角线,收集所有元素到列表 l 中。然后对列表 l 进行排序,之后将排序后的元素重新赋值回矩阵的对应位置。对于矩阵的每个可能的对角线起点,分别调用 helpSort 函数。对角线的起点分两部分:一部分是矩阵的第一行每个元素作为起点,另一部分是矩阵的第一列除第一个元素外的每个元素作为起点。

时间复杂度:

O((m + n) * min(m, n) * log(min(m, n)))

空间复杂度:

O(min(m, n))

代码细节讲解

🦆
在 helpSort 函数中,如果对角线的长度大于数组的长度,如何确保不会出现索引越界的错误?
在 helpSort 函数中,通过使用循环条件 `i < m` 和 `j < n` 确保了索引不会越界。这两个条件分别检查是否达到了矩阵的行边界和列边界,从而在对角线元素的收集过程中不会超出矩阵的实际大小。即使对角线的理论长度(从起点开始直到矩阵的一个角)可能大于矩阵的实际尺寸,这种检查确保了只有在索引有效时才会访问元素。
🦆
你是如何确定对角线上元素的起点的?对于边界条件,如何处理矩阵的最后一行或最后一列?
对角线上元素的起点是通过两个循环确定的:一个循环遍历矩阵的第一行的每个元素,另一个循环遍历矩阵的第一列的每个元素(除了第一个)。这样确保了从每个可能的起点开始处理对角线。对于矩阵的最后一行或最后一列,由于对角线始终从左上到右下方向延伸,所以起点不会位于最后一行或最后一列。因此,不需要特别处理这些边界条件,因为它们不会作为对角线的起点。
🦆
对角线上的元素排序后重新放置时,为什么可以保证不会影响到其他对角线的元素排序?
每个对角线的元素是独立处理的,因为对角线不会与其他对角线共享元素(除了在边界相交的点,此时这些点已经被定位且不再修改)。在 `helpSort` 函数中,每次都是对从特定起点开始的对角线元素进行收集、排序和重新放置。由于每个对角线处理完成后,其元素就固定下来,不会被后续对角线处理过程影响,因此可以确保一个对角线的排序不会干扰到其他对角线的元素排序。
🦆
在实际操作中,排序每个对角线是否会引入重复排序的问题,尤其是在对角线相交的情况下?
虽然对角线在矩阵的边角处会相交,但每个对角线在处理时是独立的,且每个元素只会被排序一次。相交只发生在边角单个点,这些点在它们各自对角线的处理中已经被排序。因此,不存在重复排序的问题,因为每个对角线是从其特定的起点开始独立处理,且排序操作限定在该对角线的元素上。

相关问题