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

LeetCode 1861. 旋转盒子【详细题解|双指针+模拟两种解法】

LeetCode 1861. 旋转盒子【详细题解|双指针+模拟两种解法】

一、题目概述

1.1 题目描述

给定一个m x n的字符矩阵boxGrid表示箱子侧视图,矩阵包含三种字符:

  • \#:石头,受重力影响下落

  • \*:固定障碍物,位置永远不变

  • \.:空位置

需要完成两个核心操作:

  1. 箱子顺时针旋转90度,矩阵尺寸由m\*n变为n\*m

  2. 旋转后石头受重力垂直下落,直至碰到箱子底部、障碍物或其他石头;

题目保证初始状态合法:所有石头初始都处于稳定位置(底部、石头上、障碍物上),无悬空石头。最终返回旋转+重力下落后的新矩阵。

1.2 示例展示

示例1

输入:boxGrid=[["#",".","#"]]输出:[["."],["#"],["#"]]

示例2

输入:boxGrid=[["#",".","*","."],["#","#","*","."]]输出:[["#","."],["#","#"],["*","*"],[".","."]]

1.3 数据范围

  • 1 \<= m, n \<= 500

  • 矩阵元素仅为\#、\*、\.三种字符

二、解题核心思路分析

2.1 过程拆解

本题难点在于理清旋转重力下落的先后顺序与坐标映射关系,最优解题顺序为:

先模拟重力下落(原矩阵预处理)→ 再顺时针旋转90度得到结果矩阵

原因:重力是垂直向下的,在原矩阵中,每一行的重力下落逻辑独立、简单易处理;若先旋转再处理重力,坐标逻辑会变得复杂,极易出错。

2.2 核心规律

  1. 重力规则:同一行中,障碍物会分割出独立区间,每个区间内的石头全部下沉到区间底部,空位填充到上方;

  2. 旋转坐标规则:原矩阵m行n列,旋转后为n行m列。原矩阵坐标\(i,j\)对应新矩阵坐标\(j, m\-1\-i\)

2.3 解法分类

  • 解法一:暴力模拟法:逐行遍历,分割障碍物区间,统计石头数量,重构每一行,直观易懂;

  • 解法二:双指针优化法:不开辟额外数组重构行,原地双指针移动石头,时间空间最优,适配大数据量。

三、解法一:暴力模拟预处理 + 矩阵旋转

3.1 算法思路

  1. 逐行重力预处理:遍历原矩阵每一行,以\*为分割点,将每行拆分为多个独立区间;

  2. 对每个区间,统计石头\#的数量,区间重构为:上方全为空位\.,下方全为石头\#

  3. 保留所有障碍物位置不变,拼接所有区间得到重力下落完成后的原矩阵;

  4. 矩阵旋转:按照顺时针90度坐标映射规则,生成最终结果矩阵。

3.2 完整代码实现

fromtypingimportListclassSolution:defrotateTheBox(self,boxGrid:List[List[str]])->List[List[str]]:m=len(boxGrid)n=len(boxGrid[0])# 第一步:预处理,模拟每一行石头重力下落foriinrange(m):row=boxGrid[i]new_row=[]left=0whileleft<n:# 遇到障碍物,直接加入并跳过ifrow[left]=='*':new_row.append('*')left+=1continue# 找到当前无障碍物区间的左右边界right=left stone_cnt=0whileright<nandrow[right]!='*':ifrow[right]=='#':stone_cnt+=1right+=1# 重构区间:前方空位,后方石头empty_cnt=right-left-stone_cnt new_row.extend(['.']*empty_cnt)new_row.extend(['#']*stone_cnt)left=right# 更新当前行为重力下落后的行boxGrid[i]=new_row# 第二步:顺时针旋转90度,m*n -> n*mres=[[None]*mfor_inrange(n)]foriinrange(m):forjinrange(n):res[j][m-1-i]=boxGrid[i][j]returnres

3.3 复杂度分析

  • 时间复杂度O\(m\*n\),仅两次矩阵遍历,每个格子仅访问常数次;

  • 空间复杂度O\(m\*n\),主要为结果矩阵开销,预处理行数组为临时开销。

四、解法二:双指针原地优化 + 矩阵旋转(最优解)

4.1 算法思路

暴力法需要额外数组重构每一行,双指针法可实现原地修改,节省临时数组空间,核心逻辑:

  1. 逆序遍历每一行,定义落地指针 fall:记录当前石头可以下落的最底部位置;

  2. 遇到空位\.:直接跳过;

  3. 遇到石头\#:将当前石头移动到 fall 指针位置,fall 指针上移;

  4. 遇到障碍物\*:障碍物位置不变,fall 指针更新为障碍物上一位(新的下落起点);

  5. 原地完成所有行的重力下落,再执行矩阵旋转,得到结果。

4.2 完整代码实现

fromtypingimportListclassSolution:defrotateTheBox(self,boxGrid:List[List[str]])->List[List[str]]:m=len(boxGrid)n=len(boxGrid[0])# 第一步:双指针原地处理重力下落foriinrange(m):# fall指针:当前石头可下落的最低位置,初始为行末尾fall=n-1# 逆序遍历每一列forjinrange(n-1,-1,-1):# 遇到障碍物:更新下落位置,障碍物位置保留ifboxGrid[i][j]=='*':fall=j-1# 遇到石头:移动到fall位置,fall上移elifboxGrid[i][j]=='#':boxGrid[i][j]='.'boxGrid[i][fall]='#'fall-=1# 第二步:顺时针旋转90度res=[[None]*mfor_inrange(n)]foriinrange(m):forjinrange(n):res[j][m-1-i]=boxGrid[i][j]returnres

4.3 算法优势

  • 空间更优:无临时行数组,仅使用常数额外变量,空间复杂度优化为O\(1\)(不计结果输出数组);

  • 效率更高:单次遍历完成重力模拟,代码极简,常数级开销更小;

  • 适配大数据:完美适配题目 500*500 最大数据量,无超时风险。

4.4 复杂度分析

  • 时间复杂度O\(m\*n\),两次线性遍历矩阵;

  • 空间复杂度O\(1\)额外空间(结果数组为题目必须输出,不计入算法空间开销)。

五、核心难点详解

5.1 旋转坐标映射推导

原矩阵:m行n列,旋转后:n行m列

顺时针旋转90度通用坐标公式:
原坐标\(i, j\)→ 新坐标\(j, m\-1\-i\)

推导逻辑:

  1. 原矩阵第i行,旋转后变为新矩阵倒数第i列;

  2. 原矩阵第j列,旋转后变为新矩阵第j行;

  3. 最终映射为res\[j\]\[m\-1\-i\] = boxGrid\[i\]\[j\]

5.2 重力模拟关键细节

  • 必须逆序遍历行:从行尾向行头遍历,保证石头下落时不会覆盖未遍历的石头;

  • 障碍物是天然分隔边界:每个障碍物右侧是独立的下落区间,fall指针实时重置,保证区间隔离;

  • 先置空再赋值:移动石头时先将原位置置空,再写入下落位置,避免数据覆盖错误。

六、代码测试验证

使用示例2数据测试双指针解法:

if__name__=="__main__":sol=Solution()box=[["#",".","*","."],["#","#","*","."]]print(sol.rotateTheBox(box))# 输出:[['#','.'],['#','#'],['*','*'],['.','.']]

七、总结

  1. 解题最优顺序:先重力下落、后矩阵旋转,大幅降低逻辑复杂度;

  2. 暴力法:逻辑直观、适合新手理解原理,空间开销略大;

  3. 双指针法:原地修改、时空最优,是面试刷题首选解法;

  4. 核心考点:矩阵旋转坐标映射+线性遍历模拟重力,是矩阵类经典题型。

http://www.jsqmd.com/news/765575/

相关文章:

  • Cursor智能体开发:Agent 故障排查
  • Dante Cloud v4.0.6.0 版本发布:开源新功能,支持多架构灵活切换!
  • 百万上下文之后,拼什么?
  • WeakAuras Companion终极指南:5分钟实现魔兽世界光环自动同步
  • Cortex-A7的运行模式
  • 从0到1构建奶牛行为智能监控系统(一)
  • 生物科学插图的免费宝库:Bioicons让你的科研可视化更专业
  • PubSubClient:Arduino MQTT客户端库终极指南
  • 突破反爬与动态渲染:Selenium + Chrome 深度实战
  • 你的旧安卓手机别扔!用Termux API把它改造成智能家居控制中心(支持红外/通知/传感器)
  • 告别盲猜:用Process Monitor给你的软件行为做一次“全身体检”(以Chrome/微信为例)
  • 探索模型广场功能并找到适合文本摘要任务的最佳模型
  • 从哈工大论文到你的DSP:ESO谐波抑制算法移植实战,附C代码核心片段与调试心得
  • Omdia最新研究表明:蜂窝物联网数据流量到2035年将达到218.6艾字节
  • 如何永久保存微信聊天记录:三步实现完整备份与深度分析
  • 如何让Direct3D 8游戏在现代Windows上流畅运行:d3d8to9终极指南
  • 终极音乐解锁解决方案:Unlock-Music开源工具详解
  • 零成本实现家庭服务器24小时稳定在线:luci-app-aliddns动态域名解析终极指南
  • 高效智能的免费小说下载工具:novel-downloader终极解决方案
  • Docker 27车载容器“瘦身后遗症”预警:27种轻量化陷阱与反模式(含3家头部车企实车崩溃日志分析)
  • AISMM模型五个等级——不是阶梯是悬崖:Level 3未达标=AI系统法律免责权自动失效
  • 创业团队如何利用 Taotoken 统一管理多个 AI 模型的 API 调用与成本
  • 避坑指南:在Ruoyi登录流程中集成密码强制修改,我踩了这三个Token管理的坑
  • 利用taotoken多模型能力为github开源项目构建智能助手
  • 2026届毕业生推荐的五大AI辅助写作方案推荐
  • 5分钟学会Unity游戏去马赛克:六大插件完全指南
  • 特征工程:从5个核心维度构造水果销售预测特征
  • AI根本守不住秘密!不依靠大模型的输出过滤才是铜墙铁壁
  • 打破维度边界:用开源工具将沉浸式VR视频转为传统2D格式
  • 2026 年 CS 1.6 死斗服务器开服指南(Linux)