news 2026/6/15 15:15:25

LeetCode 189. 旋转数组 | 三步反转最优解全拆解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 189. 旋转数组 | 三步反转最优解全拆解

「旋转数组」核心考察数组操作技巧空间复杂度优化思路。这道题看似简单,却能延伸出多种解题方法,从暴力模拟到极致的空间优化,层层递进的思路能帮我们理解算法设计的核心 —— 用最少的资源解决问题。实际开发中,类似循环数组操作数据位移处理等场景都能用到它的思路。今天我们从暴力解法出发,一步步优化到 O (1) 空间复杂度的最优解,带你吃透旋转数组的本质~

📌 题目重述

给你一个整数数组nums,以及一个整数k,请你将数组中的元素向右旋转k个位置。旋转规则是:数组末尾的k个元素移到数组开头,其余元素依次向右移动。
这里要注意两个关键点:

  1. k 可能大于数组长度:比如数组长度为 5,k=7,实际等效于旋转k % 5 = 2个位置(因为旋转 5 次会回到原数组);
  2. 原地旋转要求:最优解法需要在原数组上操作,不使用额外的数组空间。

举个例子,输入nums = [1,2,3,4,5,6,7]k = 3,输出应为[5,6,7,1,2,3,4](末尾 3 个元素移到开头);输入nums = [-1,-100,3,99]k = 2,输出应为[3,99,-1,-100]

🚶 阶梯思路拆解

第一步:暴力思路(逐次旋转 + 临时变量)🥾

最直观的想法是,模拟每次向右旋转 1 个位置的过程,重复k次。这种方法逻辑简单,容易理解,但效率极低,仅适合入门理解。

💡 核心逻辑

  1. 先处理k:计算k = k % nums.length(避免重复旋转);
  2. 循环k次,每次旋转 1 个位置:
    • 保存数组最后一个元素到临时变量temp
    • 从后往前遍历数组,将每个元素向右移动一位(nums[i] = nums[i-1]);
    • temp放到数组第一个位置;
  3. 循环结束后,数组即为旋转后的结果。

📊 图文演示(以 nums = [1,2,3,4,5,6,7], k=3 为例)

(如图所示)暴力旋转过程(仅展示第一次旋转):

  • 初始数组:[1,2,3,4,5,6,7]
  • 保存最后一个元素:temp = 7
  • 从后往前移动元素:
    • nums[6] = nums[5] → [1,2,3,4,5,6,6]
    • nums[5] = nums[4] → [1,2,3,4,5,5,6]
    • nums[1] = nums[0] → [1,1,2,3,4,5,6]
  • 放入临时变量:nums[0] = 7 → [7,1,2,3,4,5,6](第一次旋转完成)
  • 重复 3 次后,最终数组:[5,6,7,1,2,3,4]

✅ 代码实现(Java)

publicclassSolution{publicvoidrotate(int[]nums,intk){intn=nums.length;k=k%n;// 处理k大于数组长度的情况for(inti=0;i<k;i++){// 每次旋转1个位置inttemp=nums[n-1];// 保存最后一个元素// 从后往前移动元素for(intj=n-1;j>0;j--){nums[j]=nums[j-1];}nums[0]=temp;// 放到第一个位置}}}

⚙️ 复杂度分析

复杂度类型计算结果说明
时间复杂度O(n×k)外层循环 k 次,内层循环 n 次,最坏情况下 k=n,时间复杂度为 O (n²)
空间复杂度O(1)仅使用临时变量 temp,无额外空间开销

🚫 遇到的问题

时间效率过低!当数组长度n=10⁵k=10⁵(等效于 k=0,但实际代码会先取模),若 k=5×10⁴,n×k会达到 5×10⁹次运算,完全超出时间限制。核心问题是重复移动元素—— 每次旋转都要移动整个数组,做了大量无用功。

第二步:优化思路(额外数组存储)🗺️

为了解决暴力解法的时间问题,我们可以用额外的数组存储旋转后的结果,再复制回原数组。这种方法时间复杂度降到 O (n),但需要额外的空间。

💡 核心逻辑

  1. 处理kk = k % nums.length
  2. 创建一个与原数组长度相同的新数组newNums
  3. 遍历原数组,将每个元素放到新数组的对应位置:原数组索引i的元素,旋转后应位于(i + k) % n的位置;(或更直观:前n-k个元素移到末尾,后k个元素移到开头)
  4. 将新数组的元素复制回原数组。

📊 图文演示(以 nums = [1,2,3,4,5,6,7], k=3 为例)

(如图所示)额外数组存储过程:

  • 原数组索引:0:1, 1:2, 2:3, 3:4, 4:5, 5:6, 6:7
  • 后 k=3 个元素(索引 4、5、6)移到新数组开头:
    • newNums[0] = 5, newNums[1] = 6, newNums[2] = 7
  • 前 n-k=4 个元素(索引 0、1、2、3)移到新数组末尾:
    • newNums[3] = 1, newNums[4] = 2, newNums[5] = 3, newNums[6] = 4
  • 新数组:[5,6,7,1,2,3,4],复制回原数组即可。

✅ 代码实现(Java)

publicclassSolution{publicvoidrotate(int[]nums,intk){intn=nums.length;k=k%n;int[]newNums=newint[n];// 方法1:按“前n-k移末尾,后k移开头”处理// 后k个元素移到开头for(inti=0;i<k;i++){newNums[i]=nums[n-k+i];}// 前n-k个元素移到末尾for(inti=0;i<n-k;i++){newNums[k+i]=nums[i];}// 方法2:通用公式 (i + k) % n(两种方法等价)// for (int i = 0; i < n; i++) {// newNums[(i + k) % n] = nums[i];// }// 复制回原数组System.arraycopy(newNums,0,nums,0,n);}}

⚙️ 复杂度分析

复杂度类型计算结果说明
时间复杂度O(n)仅遍历数组两次(一次赋值新数组,一次复制回原数组),线性时间
空间复杂度O(n)需要额外的数组存储结果,空间复杂度为 O (n)

💡 优化亮点与待改进点

  • 亮点:时间复杂度从 O (n²) 降到 O (n),效率大幅提升,能应对大规模数据;
  • 待改进:需要额外的 O (n) 空间,不符合原地旋转的最优要求(面试中通常会要求原地操作)。

第三步:最优解法(三步反转法 / 原地旋转)🔑

这是本题的最优解:利用数组反转的特性,通过三次反转实现原地旋转,时间复杂度 O (n),空间复杂度 O (1)。核心思想是将旋转问题转化为反转问题

先理解反转的特性

  • 反转整个数组:[1,2,3,4,5,6,7] → [7,6,5,4,3,2,1]
  • 反转前 k 个元素:[7,6,5,4,3,2,1] → [5,6,7,4,3,2,1]
  • 反转后 n-k 个元素:[5,6,7,4,3,2,1] → [5,6,7,1,2,3,4](最终结果)。

💡 核心逻辑

  1. 处理kk = k % nums.length
  2. 第一步反转:反转整个数组;
  3. 第二步反转:反转数组前k个元素;
  4. 第三步反转:反转数组后n-k个元素;
  5. 三次反转完成后,数组即为旋转后的结果。

📊 图文演示(以 nums = [1,2,3,4,5,6,7], k=3 为例)

(如图所示)三步反转过程:

  1. 反转整个数组:
    [1,2,3,4,5,6,7] → [7,6,5,4,3,2,1]
  2. 反转前 k=3 个元素:
    [7,6,5,4,3,2,1] → [5,6,7,4,3,2,1]
  3. 反转后 n-k=4 个元素:
    [5,6,7,4,3,2,1] → [5,6,7,1,2,3,4](旋转完成)

✅ 代码实现(Java,最优解)

publicclassSolution{publicvoidrotate(int[]nums,intk){intn=nums.length;k=k%n;// 处理k大于数组长度的情况reverse(nums,0,n-1);// 反转整个数组reverse(nums,0,k-1);// 反转前k个元素reverse(nums,k,n-1);// 反转后n-k个元素}// 辅助方法:反转数组中[start, end]区间的元素privatevoidreverse(int[]nums,intstart,intend){while(start<end){// 交换start和end位置的元素inttemp=nums[start];nums[start]=nums[end];nums[end]=temp;start++;end--;}}}

⚙️ 复杂度分析

复杂度类型计算结果说明
时间复杂度O(n)三次反转总共遍历数组 n 次(反转整个数组 n 次,前 k 和后 n-k 共 n 次),线性时间
空间复杂度O(1)仅使用临时变量交换元素,原地操作,无额外空间开销

✨ 核心优势

  1. 时间最优:O (n) 时间复杂度,效率与额外数组法相同;
  2. 空间最优:O (1) 空间复杂度,完全原地操作,满足面试最优要求;
  3. 逻辑巧妙:将旋转转化为反转,思路清晰,代码简洁易记。

第四步:边界情况与易错点

常见边界场景

  1. k=0(或 k 是数组长度的倍数):数组无需旋转,直接返回原数组(代码中k%n会处理为 0,三次反转后数组不变);
  2. 数组长度为 1:无论 k 是多少,数组都不会变化;
  3. k=1:等效于暴力解法的一次旋转,三步反转法同样适用;
  4. 数组元素全相同:旋转后结果不变,所有方法都能正确处理。

易错点提醒

  • 忘记处理 k:直接使用原始 k 值,当 k>n 时会导致数组越界或重复旋转;
  • 反转区间错误:第三步反转的起始索引是k而非k+1(比如 k=3,后 n-k 个元素从索引 3 开始);
  • 反转函数实现错误:交换元素时未正确移动startend指针(如遗漏start++end--)。

📝 总结

「旋转数组」的解题思路,核心是从暴力模拟到空间优化的递进:

  1. 暴力解法:逐次旋转,直观但效率低(O (n²) 时间);
  2. 额外数组法:空间换时间,效率提升但需要 O (n) 空间;
  3. 三步反转法:最优解,利用反转特性实现原地旋转(O (n) 时间 + O (1) 空间)。

关键技巧可以总结为:

  • 处理 k 的通用方法:k = k % n(避免重复操作);
  • 旋转与反转的转化:向右旋转 k 个位置 = 三次反转(整体→前 k→后 n-k);
  • 原地操作的核心:通过交换元素实现反转,不使用额外空间。

同类题扩展建议

掌握了这道题的思路后,可以尝试这些进阶题目:

  1. LeetCode 33. 搜索旋转排序数组:旋转数组的延伸,考察二分查找的变种;
  2. LeetCode 153. 寻找旋转排序数组中的最小值:旋转排序数组的最小值查找,同样用二分优化;
  3. LeetCode 48. 旋转图像:二维数组的旋转,思路与本题的反转法类似;
  4. LeetCode 61. 旋转链表:链表的旋转操作,考察链表指针的移动技巧。

旋转类问题的核心是找到元素的新位置,无论是数组还是链表,掌握位置映射的规律就能轻松解决~

📢 关注不迷路,算法学习更高效!

如果这篇拆解对你有帮助,别忘了关注我的微信公众号【小镇冥想人】~ 后续会持续更新 LeetCode 高频题的阶梯式解题思路,从暴力到最优解层层递进,每道题都搭配详细图文和代码注释,帮你轻松攻克算法难关。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 11:17:31

【YOLO11-MM 多模态目标检测】动态门控MCFGatedFusion特征融合【自研模块】、抛弃Concat、实现特征动态补偿

摘要 本文提出了一种基于动态门控特征融合模块(MCFGatedFusion)的YOLO11-MM多模态目标检测框架改进方案。该模块通过可学习的门控机制实现红外与可见光特征的自适应融合,采用零初始化策略确保训练稳定性,支持add和concat两种融合模式。实验表明,该方法在FLIR、M3FD等数据…

作者头像 李华
网站建设 2026/6/15 4:33:54

腾讯AngelSlim开源项目深度解析:AI驱动的开发者协作新范式

在当今数字化浪潮席卷全球的背景下&#xff0c;开源社区已成为推动技术创新的核心引擎。腾讯作为全球领先的互联网科技公司&#xff0c;始终积极投身开源事业&#xff0c;近日其在Gitcode平台上发布的AngelSlim项目引发了业界广泛关注。该项目以222星标和26次分支 Fork 的成绩&…

作者头像 李华
网站建设 2026/6/15 15:00:09

Linux基础命令和工具详解,让你轻松应对各种任务!

grep 命令用于在文件中执行关键词搜索&#xff0c;并显示匹配的效果。部分常用选项 &#xff1a;-c 仅显示找到的行数-i 忽略大小写-n 显示行号-v 反向选择 – 仅列出没有关键词的行。v 是 invert 的缩写。-r 递归搜索文件目录-C n 打印匹配行的前后n行&#xff08;1&#xff0…

作者头像 李华
网站建设 2026/6/15 15:02:01

DPDK技术详解:工作原理与环境搭建实践指南

网卡作为 ssh 连接的网卡。&#xff08;2&#xff09;修改网卡配置信息。找到虚拟机安装目录下的.vmx文件&#xff0c;内容如下&#xff1a;展开代码语言&#xff1a;Bash自动换行AI代码解释.encoding "GBK" config.version "8" virtualHW.version &quo…

作者头像 李华
网站建设 2026/6/15 12:04:25

JavaScript学习

为什么学习 JavaScript&#xff1f;JavaScript 不仅是 Web 开发的三大核心技术之一&#xff0c;更是全栈开发的通行证。根据 Stack Overflow 2023 开发者调查&#xff0c;JavaScript 连续 11 年位居最流行编程语言榜首&#xff0c;市场需求巨大。JavaScript 学习路径基础语法与…

作者头像 李华
网站建设 2026/6/15 15:04:11

5个秘诀让你的Windows右键菜单秒响应:终极解决方案揭秘

5个秘诀让你的Windows右键菜单秒响应&#xff1a;终极解决方案揭秘 【免费下载链接】ContextMenuManager &#x1f5b1;️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager "每次右键都要等上好几秒&#xff0c;那…

作者头像 李华