当前位置: 首页 > news >正文

【LeetCode 每日一题】3446. 按对角线进行矩阵排序——(解法一)分组 - 排序 - 重建

Problem: 3446. 按对角线进行矩阵排序

文章目录

  • 整体思路
  • 完整代码
  • 时空复杂度
    • 时间复杂度:O(N^3)
    • 空间复杂度:O(N^2)

整体思路

这段代码旨在解决一个非常特殊的矩阵排序问题:对一个 n x n 的方阵 grid,将其主对角线方向(从左上到右下)的每一条对角线上的元素进行排序,然后用排序后的元素重构矩阵。排序规则是:主对角线(从 (0,0)(n-1,n-1))及其下方的所有对角线按降序排序,而主对角线上方的所有对角线按升序排序。

算法采用了一种分步处理的策略:分组 -> 排序 -> 重建

  1. 第一步:按对角线分组

    • 算法的核心是识别出哪些元素属于同一条对角线。它利用了一个数学特性:对于同一条主对角线方向的对角线上的任意元素 (i, j),它们的行索引和列索引之差 i - j 是一个常数
    • 代码通过 int p = i - j + n - 1; 这个公式将每个 (i, j) 映射到一个对角线索引 p
      • i - j 的范围是 -(n-1)n-1
      • 加上 n-1 这个偏移量,使得索引 p 的范围变为 02n-2,这正好对应了矩阵中 2n-1 条不同的对角线,方便地用作列表的索引。
    • 一个 List<List<Integer>> dia 被用来存储分组结果,dia.get(p) 就是第 p 条对角线上的所有元素。
  2. 第二步:对每条对角线进行排序

    • 算法遍历每一条对角线(即 dia 中的每一个列表)。
    • 它根据对角线的索引 i (也就是 p) 来决定排序规则:
      • 主对角线对应的索引是 p = (i - i) + n - 1 = n - 1
      • 升序排序:如果 i < n - 1,说明这是主对角线上方的对角线,使用 (a, b) -> a - b 进行升序排序。
      • 降序排序:如果 i >= n - 1,说明这是主对角线或其下方的对角线,使用 (a, b) -> b - a 进行降序排序。
  3. 第三步:重建排序后的矩阵

    • 最后,算法再次遍历 n x n 矩阵的每一个位置 (i, j)
    • 对于每个位置,它再次使用 p = i - j + n - 1 计算出其所属的对角线索引。
    • 然后,它从 dia.get(p) 这个已排序的列表中取出第一个元素(get(0)),并将其放入新矩阵 ans[i][j] 的相应位置。
    • 为了确保下一次访问同一条对角线时能取到下一个正确的元素,它将刚刚用过的元素从列表中移除remove(0))。

完整代码

import java.util.ArrayList;
import java.util.List;class Solution {/*** 对矩阵的对角线进行特殊排序。* 主对角线上方的对角线升序排序,主对角线及下方的对角线降序排序。* @param grid 输入的 n x n 方阵* @return 排序后的新矩阵*/public int[][] sortMatrix(int[][] grid) {int n = grid.length;int[][] ans = new int[n][n];// dia: 用于存储按对角线分组的元素List<List<Integer>> dia = new ArrayList<>();// 一个 n x n 矩阵共有 2n-1 条主对角线方向的对角线for (int i = 0; i < 2 * n - 1; i++) {dia.add(new ArrayList<>());}// 步骤 1: 遍历原矩阵,将元素按对角线分组for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {// 关键公式:i - j 对于同一条对角线是常数。// + (n - 1) 是为了将索引映射到 [0, 2n-2] 的非负区间。int p = i - j + n - 1;dia.get(p).add(grid[i][j]);}}// 步骤 2: 遍历所有对角线列表,并根据规则进行排序for (int i = 0; i < 2 * n - 1; i++) {// 主对角线的索引是 n-1。// i < n-1 表示是主对角线上方的对角线if (i < n - 1) {dia.get(i).sort((a, b) -> a - b); // 升序} else { // 主对角线及下方的对角线dia.get(i).sort((a, b) -> b - a); // 降序}}// 步骤 3: 遍历新矩阵的位置,从排好序的对角线列表中取值填充for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {// 再次计算位置 (i, j) 对应的对角线索引 pint p = i - j + n - 1;// 从对角线 p 的列表中取出第一个元素ans[i][j] = dia.get(p).get(0);// 【效率瓶颈】将用过的元素从列表头部移除dia.get(p).remove(0); }}return ans;}
}

时空复杂度

时间复杂度:O(N^3)

  1. 分组循环:第一个嵌套 for 循环遍历 N x N 矩阵一次,内部操作为 O(1)。总时间为 O(N^2)
  2. 排序循环
    • 外层循环执行 2N-1 次。
    • 内层是对每个对角线列表进行排序。设第 i 条对角线的长度为 L_i,排序时间为 O(L_i log L_i)
    • 所有对角线的总元素数 Σ L_i = N^2。最长的对角线有 N 个元素。
    • 总排序时间为 Σ O(L_i log L_i),其上界为 O(N^2 log N)
  3. 重建循环
    • 第三个嵌套 for 循环遍历 N x N 矩阵一次。
    • 关键瓶颈:循环内部的 dia.get(p).remove(0) 操作。对于 ArrayList,从头部移除一个元素的时间复杂度是 O(L),其中 L 是列表的当前长度,因为需要将后续所有元素向前移动一位。
    • 考虑一条长度为 L 的对角线,在重建过程中,会依次执行 remove(0)L 次。总操作数约为 L + (L-1) + ... + 1,即 O(L^2)
    • 由于最长的对角线长度为 N,仅处理这条对角线就需要 O(N^2) 的时间。而所有对角线长度的平方和 Σ L_i^2 大致是 O(N^3) 级别。因此,重建这一步的时间复杂度是 O(N^3)

综合分析
总时间复杂度由最慢的部分决定:O(N^2) + O(N^2 log N) + O(N^3)。因此,最终的时间复杂度是 O(N^3),瓶颈在于重建矩阵时低效的 remove(0) 操作。

空间复杂度:O(N^2)

  1. 主要存储开销
    • List<List<Integer>> dia: 这个数据结构需要存储原始矩阵中的所有 N^2 个元素。因此,它占用的空间是 O(N^2)
    • int[][] ans: 输出矩阵,也占用 O(N^2) 的空间。

综合分析
算法需要一个与原矩阵同样大小的辅助数据结构来存储分组后的对角线元素。因此,其额外辅助空间复杂度为 O(N^2)


文章转载自:

http://rKPeBTB1.qLsyf.cn
http://rdjqokNU.qLsyf.cn
http://eU50Jw8B.qLsyf.cn
http://ciZRKUJH.qLsyf.cn
http://Jw89Xii5.qLsyf.cn
http://OApczBhJ.qLsyf.cn
http://hBvVktO4.qLsyf.cn
http://sczqNY9H.qLsyf.cn
http://NYtrg1Je.qLsyf.cn
http://aOgIEn9I.qLsyf.cn
http://JKZUJpI0.qLsyf.cn
http://YeIayMhj.qLsyf.cn
http://fyLEfFJu.qLsyf.cn
http://vuXbgy07.qLsyf.cn
http://xx6HcxzS.qLsyf.cn
http://XRFB9Gkr.qLsyf.cn
http://l356kF57.qLsyf.cn
http://9CLtLD6q.qLsyf.cn
http://ohhe33SR.qLsyf.cn
http://plqIaBnh.qLsyf.cn
http://7Wd5KE5F.qLsyf.cn
http://B3jvd9Tn.qLsyf.cn
http://hV6o9SGk.qLsyf.cn
http://jBUCHzQ8.qLsyf.cn
http://irflGBts.qLsyf.cn
http://ZoEHnShr.qLsyf.cn
http://om77E9xi.qLsyf.cn
http://2ru2NyJP.qLsyf.cn
http://4qP8zBPa.qLsyf.cn
http://kWQjLMLz.qLsyf.cn
http://www.dtcms.com/a/382252.html

相关文章:

  • 【亲测有效】解决 “Batch script contains DOS line breaks (\r\n)” 报错
  • 集值优化问题:理论、应用与前沿进展
  • 17、逻辑回归与分类评估 - 从连续到离散的智能判断
  • AMD KFD的BO设计分析系列3-1: GTT的实现分析
  • 如何实现静态库与动态库的制作
  • 【硬件开发】电源抑制比PSRR
  • 基于Redisson的分布式锁原理深度解析与性能优化实践指南
  • 【Leetcode hot 100】101.对称二叉树
  • 破解多校区高校运维困局,协同效率提升60%的智能运维方案
  • 王道计算机组成原理 学习笔记
  • Matplotlib:绘制你的第一张折线图与散点图
  • 即梦批量生成图片软件使用运营大管家-即梦图片批量生成器
  • Qt中解析JSON文件
  • 从静态表查询冲突到其原理
  • Git 版本回退与撤销修改
  • Tcpdump: The Basics Tcpdump 基础
  • 智慧物联网水利大数据平台建设方案PPT(70页)
  • 字典树初步
  • GitHub 热榜项目 - 日榜(2025-09-13)
  • 18、决策树与集成学习 - 从单一智慧到群体决策
  • 基于 Spring 的策略模式框架,用于根据不同的类的标识获取对应的处理器实例
  • Python:OpenCV 教程——从传统视觉到深度学习:YOLOv8 与 OpenCV DNN 模块协同实现工业缺陷检测
  • UTC时间戳转换
  • 【Unity进阶】Unity发布PC端,隐藏并自定义默认标题栏
  • 【Qt】编写Qt自定义Ui控件步骤
  • HTTP 状态码背后的逻辑:从请求到响应的完整流程解析(含完整流程图)
  • 如何规划活动宣传软文的发布节奏?
  • 什么是NTP?
  • n8n工作流平台入门学习指南
  • JVM 四大晋升机制