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

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

LeetCode 3446. 按对角线进行矩阵排序 - 从复杂到简洁的优化思考

题目描述

给你一个大小为 n x n 的整数方阵 grid。返回一个经过如下调整的矩阵:

  • 左下角三角形(包括中间对角线)的对角线按 非递增顺序 排序
  • 右上角三角形 的对角线按 非递减顺序 排序

示例

示例 1:

输入: grid = [[1,7,3],[9,8,2],[4,5,6]]
输出: [[8,2,3],[9,6,7],[4,5,1]]

示例 2:

输入: grid = [[0,1],[1,2]]
输出: [[2,1],[1,0]]

解题思路的演进

第一版:收集-排序-放回

最初的想法是传统的排序方法:

def sortMatrix(self, grid: List[List[int]]) -> List[List[int]]:n = len(grid)if n <= 1:return grid# 处理左下角三角形 - 非递增排序for i in range(n):r, c = i, 0diagonal_length = min(n - i, n)# 收集当前对角线的元素diagonal = []for j in range(diagonal_length):diagonal.append(grid[r + j][c + j])# 对对角线元素进行非递增排序diagonal.sort(reverse=True)# 将排序后的元素放回原位置for j in range(diagonal_length):grid[r + j][c + j] = diagonal[j]# 处理右上角三角形 - 非递减排序for j in range(1, n):r, c = 0, jdiagonal_length = min(n, n - j)# 收集当前对角线的元素diagonal = []for l in range(diagonal_length):diagonal.append(grid[r + l][c + l])# 对对角线元素进行非递减排序diagonal.sort()# 将排序后的元素放回原位置for l in range(diagonal_length):grid[r + l][c + l] = diagonal[l]return grid

问题: 需要额外的内存空间存储对角线元素,时间复杂度 O(n² log n)

第二版:插入排序优化

为了减少内存分配,改用插入排序:

def sortMatrix(self, grid: List[List[int]]) -> List[List[int]]:n = len(grid)if n <= 1:return grid# 处理左下角三角形 - 非递增排序for i in range(n):r, c = i, 0diagonal_length = min(n - i, n)# 使用插入排序进行非递增排序(降序)for j in range(1, diagonal_length):key = grid[r + j][c + j]k = j - 1# 将大于key的元素向后移动while k >= 0 and grid[r + k][c + k] < key:grid[r + k + 1][c + k + 1] = grid[r + k][c + k]k -= 1grid[r + k + 1][c + k + 1] = key# 处理右上角三角形 - 非递减排序for j in range(1, n):r, c = 0, jdiagonal_length = min(n, n - j)# 使用插入排序进行非递减排序(升序)for l in range(1, diagonal_length):key = grid[r + l][c + l]k = l - 1# 将大于key的元素向后移动while k >= 0 and grid[r + k][c + k] > key:grid[r + k + 1][c + k + 1] = grid[r + k][c + k]k -= 1grid[r + k + 1][c + k + 1] = keyreturn grid

优化点: 空间复杂度降为 O(1),但时间复杂度变为 O(n³)

第三版:误解与纠正

在优化过程中,我产生了一个误解:

错误想法: 如果只需要"非递增"和"非递减",那么只需要一次交换就能破坏严格递增/递减性质

# 错误版本 - 只交换一次
for j in range(diagonal_length - 1):if grid[r + j][c + j] < grid[r + j + 1][c + j + 1]:grid[r + j][c + j], grid[r + j + 1][c + j + 1] = grid[r + j + 1][c + j + 1], grid[r + j][c + j]break  # 只需要交换一次

问题分析:

  • 对于 [1,8,6],交换一次变成 [8,1,6],虽然破坏了递增,但不是完全降序
  • 题目要求的是完整的排序,不是仅仅破坏递增/递减性质

最终版:简洁高效的实现

经过多次思考和验证,最终确定了正确的算法:

from typing import Listclass Solution:def sortMatrix(self, grid: List[List[int]]) -> List[List[int]]:n = len(grid)if n <= 1:return grid# 左下角三角形 - 非递增排序(降序)for i in range(n):r, c = i, 0l = min(n - i, n)# 收集对角线元素d = []for j in range(l):d.append(grid[r + j][c + j])# 降序排序d.sort(reverse=True)# 放回for j in range(l):grid[r + j][c + j] = d[j]# 右上角三角形 - 非递减排序(升序)for j in range(1, n):r, c = 0, jl = min(n, n - j)# 收集对角线元素d = []for k in range(l):d.append(grid[r + k][c + k])# 升序排序d.sort()# 放回for k in range(l):grid[r + k][c + k] = d[k]return grid

关键理解点

1. "非递增"和"非递减"的真正含义

  • 非递增顺序 = 降序排列,可以包含相等元素
  • 非递减顺序 = 升序排列,可以包含相等元素

2. 为什么不能只用一次交换?

错误理解: 一次交换就能破坏严格递增/递减性质

正确理解: 需要完整的排序才能满足题目要求

举例说明:

  • 输入:[1,8,6]
  • 错误做法:交换一次 → [8,1,6] ❌
  • 正确做法:完整排序 → [8,6,1] ✅

3. 算法复杂度分析

版本时间复杂度空间复杂度特点
第一版O(n² log n)O(n)传统方法,内存开销大
第二版O(n³)O(1)插入排序,原地操作
最终版O(n² log n)O(n)平衡了效率和简洁性

总结

这道题目教会了我几个重要的编程思维:

  1. 仔细理解题目要求:不能想当然地简化问题
  2. 验证算法正确性:通过具体例子验证思路
  3. 权衡效率与简洁:在时间复杂度和代码可读性之间找到平衡
  4. 持续优化:从复杂到简单,不断改进算法

最终,虽然我回到了"收集-排序-放回"的基本思路,但通过这个过程,我更深刻地理解了算法的本质和优化的边界。


标签: #LeetCode #算法优化 #矩阵排序 #对角线排序 #Python

更新日期2025年8月28日

http://www.xdnf.cn/news/1380601.html

相关文章:

  • UE5提升分辨率和帧率的方法
  • 搭建私有云3步法:cpolar简化Puter本地云端配置
  • C# SIMD编程实践:工业数据处理性能优化案例
  • C++ 哈希概念版
  • 【实战笔记】OCI Ubuntu 24.04 + TigerVNC + XFCE + Chrome 开机自启全记录
  • 错误模块路径: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
  • 从卡顿到丝滑:大型前端项目 CSS 优化全攻略
  • [高并发系统设计] - 搭建高并发高可用的系统 - 学习与探究
  • 【大前端】React useEffect 详解:从入门到进阶
  • Shi-Tomasi 算法和 Harris 角点检测算法都是经典的角点检测方法,但它们在理论基础和实现细节上有一些区别。下面我将详细对比这两种算法。
  • List<Map<String, String>>最简单的遍历方式
  • 【传奇开心果系列】Flet框架带图标带交互动画的办公用品费用占比统计饼图自定义模板
  • GitHub 热榜项目 - 日榜(2025-08-28)
  • 达梦数据库-重做日志文件(一)
  • 云计算学习100天-第30天
  • 09- AI大模型-docker部署dify以及 dify的使用案例:公司智能助手(构建知识库)(上篇)
  • TDengine 数据订阅支持 MQTT 协议用户手册
  • 【SQL】计算一年内每个月份的周数据
  • 上海控安:WiFi网络安全攻击
  • SONiC 之 Testbed(2)Ansible
  • GeoScene Maps 完整入门指南:从安装到实战
  • Android稳定性问题的常见原因是什么
  • 【python】@staticmethod装饰器
  • 同一个栅格数据,为何在QGIS和ArcGIS Pro中打开后显示的数值范围不同?
  • 苍穹外卖项目笔记day01
  • 【VSCode】使用VSCode打开md文件以及转化为PDF
  • uni-app 网络请求与后端交互完全指南:从基础到实战
  • ckman部署的clickhouse,节点迁移
  • Logstash数据迁移之es-to-kafka.conf详细配置
  • 用 Docker 玩转 Kafka 4.0镜像选型、快速起步、配置持久化与常见坑