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

【力扣100题】58.轮转数组

题目描述

给定一个整数数组nums,将数组中的元素向右轮转k个位置,其中k是非负数。

示例

示例 1: 输入:nums = [1,2,3,4,5,6,7], k = 3 输出:[5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,4] 示例 2: 输入:nums = [-1,-100,3,99], k = 2 输出:[3,99,-1,-100] 解释: 向右轮转 1 步: [99,-1,-100,3] 向右轮转 2 步: [3,99,-1,-100]

提示:

  • 1 <= nums.length <= 10^5
  • -2^31 <= nums[i] <= 2^31 - 1
  • 0 <= k <= 10^5

解题思路总览

方法核心思想时间复杂度空间复杂度备注
三次翻转先整体翻转,再分别翻转两段O(n)O(1)推荐解法,最优
环状替换每个元素放到最终位置O(n)O(1)需要处理 gcd
暴力法每次轮转一个元素O(n*k)O(1)会超时
额外数组借助临时数组O(n)O(n)最简单但空间不优

一、三次翻转法(最常用)

核心思想

通过三次反转操作,将数组向右轮转 k 位:

原数组: [1,2,3,4,5,6,7], k = 3 第一步:整体翻转 reverse(nums, 0, n-1) [7,6,5,4,3,2,1] 第二步:翻转前 k 个元素 reverse(nums, 0, k-1) [5,6,7,4,3,2,1] 第三步:翻转后 n-k 个元素 reverse(nums, k, n-1) [5,6,7,1,2,3,4] 结果:[5,6,7,1,2,3,4]

图解

nums = [1,2,3,4,5,6,7], k = 3 初始状态: [1, 2, 3, 4, 5, 6, 7] 0 1 2 3 4 5 6 第一步:reverse(0, 6) [7, 6, 5, 4, 3, 2, 1] 第二步:reverse(0, 2) [5, 6, 7, 4, 3, 2, 1] 第三步:reverse(3, 6) [5, 6, 7, 1, 2, 3, 4] 输出: [5,6,7,1,2,3,4]

代码实现

classSolution{public:voidrotate(vector<int>&nums,intk){k%=nums.size();// 取模,防止 k 大于数组长度ranges::reverse(nums);// 整体翻转 [1,2,3,4,5,6,7] -> [7,6,5,4,3,2,1]reverse(nums.begin(),nums.begin()+k);// 翻转前 k 个 [7,6,5] -> [5,6,7]reverse(nums.begin()+k,nums.end());// 翻转后 n-k 个 [4,3,2,1] -> [1,2,3,4]}};

二、算法流程图

详细过程(以 nums = [1,2,3,4,5,6,7], k = 3 为例)

输入: nums = [1,2,3,4,5,6,7], k = 3 Step 1: k %= n n = 7, k = 3 % 7 = 3 Step 2: ranges::reverse(nums) 翻转整个数组 [1,2,3,4,5,6,7] -> [7,6,5,4,3,2,1] Step 3: reverse(nums.begin(), nums.begin()+k) 翻转前 3 个元素 [7,6,5] [7,6,5,4,3,2,1] -> [5,6,7,4,3,2,1] Step 4: reverse(nums.begin()+k, nums.end()) 翻转后 4 个元素 [4,3,2,1] [5,6,7,4,3,2,1] -> [5,6,7,1,2,3,4] 输出: [5,6,7,1,2,3,4]

边界情况处理

情况 1: k = 0 k %= n = 0 整体翻转 + 翻转前 0 个 + 翻转后 n 个 = 整体翻转再整体翻转 = 不变 结果正确 情况 2: k = n(数组长度) k %= n = 0 相当于没有轮转 结果正确 情况 3: k > n 例如 n=7, k=10 k %= n = 3 等价于轮转 3 位 结果正确

三、逐行解析

k%=nums.size();
  • 取模,防止 k 大于数组长度
  • 例如 n=7, k=10,k %= 7 = 3,等价于轮转 3 位
  • 当 k = 0 或 k = n 时,结果和原数组一样
ranges::reverse(nums);
  • C++20 的ranges::reverse,整体翻转数组
  • [1,2,3,4,5,6,7]->[7,6,5,4,3,2,1]
  • 也可以用reverse(nums.begin(), nums.end())
reverse(nums.begin(),nums.begin()+k);
  • 翻转前 k 个元素
  • [7,6,5,4,3,2,1]->[5,6,7,4,3,2,1]
  • 此时前 k 位已经在正确位置
reverse(nums.begin()+k,nums.end());
  • 翻转后 n-k 个元素
  • [5,6,7,4,3,2,1]->[5,6,7,1,2,3,4]
  • 完成所有调整

四、为什么三次翻转能实现轮转?

数学证明

设数组长度为 n,轮转 k 位。 整体翻转后:原数组 [0...n-1] 变为 [n-1...0] 前 k 位翻转:[n-1...n-k] 变为 [n-k...n-1] 后 n-k 位翻转:[n-k-1...0] 变为 [n-k...n-1...0] 最终结果:[n-k...n-1] + [0...n-k-1] = 轮转后的正确顺序 证毕。

直观理解

原始数组: [1,2,3,4,5,6,7] 目标: [5,6,7,1,2,3,4] = 后k位 + 前n-k位 观察: - 后 k 位 [5,6,7] 在原数组中是前 n-k 位 - 前 n-k 位 [1,2,3,4] 在原数组中是后 n-k 位 三次翻转的作用: 1. 整体翻转 -> 把顺序反过来 2. 翻转前 k -> 把后 k 位翻到前面(但顺序反了) 3. 翻转后 n-k -> 把前 n-k 位翻到后面(顺序也反了) 两个"反了"抵消,最终得到正确顺序。

五、环状替换法

核心思想

每个元素直接放到最终位置,通过换手处理。

nums = [1,2,3,4,5,6,7], k = 3 数组下标对应关系: 原位置 0 -> 新位置 (0+k) % n = 3 原位置 1 -> 新位置 (1+k) % n = 4 原位置 2 -> 新位置 (5) % n = 5 原位置 3 -> 新位置 (6) % n = 6 原位置 4 -> 新位置 (0) % n = 0 (回到起点) 原位置 5 -> 新位置 (1) % n = 1 原位置 6 -> 新位置 (2) % n = 2 从位置 0 开始,顺时针走: 0 -> 3 -> 6 -> 2 -> 5 -> 1 -> 4 -> 0 形成一个环,共 7 个元素
classSolution{public:voidrotate(vector<int>&nums,intk){k%=nums.size();intn=nums.size();intcount=0;// 已放置的元素个数for(intstart=0;count<n;start++){intcurr=start;intprev=nums[start];do{intnext=(curr+k)%n;inttemp=nums[next];nums[next]=prev;prev=temp;curr=next;count++;}while(curr!=start);count++;// 补偿最后一次多减的}}};

与三次翻转法对比

维度三次翻转环状替换
代码复杂度简单,3行搞定复杂,需要处理环
空间复杂度O(1)O(1)
时间复杂度O(n)O(n)
边界处理自动处理需要处理 gcd 防止死循环

六、复杂度分析

方法时间复杂度空间复杂度备注
三次翻转O(n)O(1)推荐,最简单
环状替换O(n)O(1)需要小心处理
暴力法O(n*k)O(1)会超时
额外数组O(n)O(n)最简单但空间不优

详细分析:

三次翻转: 翻转 1: O(n) 翻转 2: O(k) 翻转 3: O(n-k) 总计: O(n) + O(k) + O(n-k) = O(n) 空间: 原地翻转,使用常数额外空间 O(1)

七、面试追问 FAQ

问题回答要点
Q: 为什么三次翻转能实现轮转?整体翻转改变顺序,前后分别翻转抵消了整体翻转带来的逆序,最终得到正确顺序
Q: k %= n 的作用是什么?防止 k 大于数组长度,k=10, n=7 等价于 k=3,避免不必要的翻转
Q: 能否只翻转一次?不能,一次翻转只能反转顺序,无法实现轮转
Q: 三次翻转的时间复杂度是多少?O(n),三次翻转的总时间之和为 O(n)
Q: 环状替换和三次翻转哪个更好?三次翻转代码更简单,面试中推荐;环状替换需要处理 gcd,较复杂
Q: 如何向左轮转?将 k 改为 n-k,或者修改翻转顺序:先翻前后两段,再整体翻转
Q: 能用队列模拟吗?可以,每次 pop_front 再 push_back,但时间复杂度 O(n*k),会超时

八、相关题目

题目编号题目名称难度核心差异
189轮转数组中等基础题,向右轮转
61旋转链表中等旋转链表,非数组
151反转字符串中的单词中等先整体翻转再分段翻转
796旋转字符串简单判断是否为旋转串
剑指 Offer 58左旋转字符串简单向左轮转

九、总结

要点内容
核心思想三次翻转:整体 -> 前k -> 后n-k
关键操作k %= n防止越界
时间复杂度O(n)(三次翻转)
空间复杂度O(1)(原地操作)
代码行数仅 4 行,简洁高效
注意事项k 可能大于 n,需要取模
变形向左轮转:将 k 改为 n-k,或修改翻转顺序

三次翻转法是轮转数组的最优解,代码简洁,面试中容易通过,建议熟练掌握。


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

相关文章:

  • 2026年质量好的高分子合金电缆桥架厂家怎么选 - 品牌排行榜
  • 普通用户如何用好Gemini3.5提升日常效率实战指南
  • 电商品牌视觉设计,哈尔滨问道品牌设计公司怎么样? - mypinpai
  • 构建有记忆的AI调解员:持久化智能体记忆与多策略检索实践
  • NVIDIA Profile Inspector 终极指南:解锁显卡隐藏设置,游戏性能飙升200%
  • 2026年天津西装定制权威指南:五大品牌深度测评与选购策略 - 品牌企业推荐师(官方)
  • 别再用记事本写网页了!Dreamweaver CS6零基础入门,手把手教你搭建第一个个人网站
  • PTO ISA 指令架构 - PTO虚拟指令集架构解析
  • 保姆级教程:用VMware Workstation Pro 16给虚拟机装Win11,告别物理硬盘引导的麻烦
  • Altium Designer 19出Gerber文件,我踩过的这些坑你千万别再踩(附完整配置截图)
  • 【2024最新实测数据】ChatGPT生成购物清单准确率达86.7%——但仅当满足这4个前提条件
  • 2026年种草短视频拍摄剪辑公司排名前五专业深度测评 - 羊城派
  • 惠州本地财税公司哪家好?品泰财务靠谱吗? - mypinpai
  • 别再死磕梯形图了!IEC 61131-3标准下的6种PLC编程语言,新手到底该选哪个?
  • 如何高效构建个人数字图书馆:番茄小说下载器完整指南
  • 百度网盘提取码智能获取终极指南:告别繁琐搜索的3秒解决方案
  • 航空行业专用实时仿真系统
  • 实战:用cpca+folium为你的门店客户地址数据绘制一张热力图(Python教程)
  • 揭秘微信机器人背后的“间谍”技术:从DLL注入到RPC通信的完整实战解析(WeChatFerry项目拆解)
  • 靠谱的1mvoc释放量测试仓厂商推荐与口碑评价 - mypinpai
  • 2026年宝钢HC950/1310DP吉帕钢推荐:高强双相冷轧汽车钢,轻量化与碰撞吸能性能优选解析 - 品牌企业推荐师(官方)
  • AI Gateway:大模型应用架构中的关键中间层与核心能力解析
  • 基于全同态加密的模型可解释性:CipherExplain实现隐私与合规兼得
  • 原神帧率解锁终极指南:5分钟突破60帧限制的完整教程 [特殊字符]
  • AI生成前端代码质量自动化评审工具的设计与实现
  • 干货指南:口碑好的电动蝶阀厂,斯帝尔服务完善多少钱 - mypinpai
  • Kiro Web 来了:浏览器里直接用 AI 写代码,不装 IDE 也能 Spec-Driven 开发
  • 智能电网边缘计算:基于LSTM的动态电价预测与HDTG任务调度实践
  • VSAR 应用发布:如何把工程能力「打包成给客户用的独立程序」
  • 避坑指南:从ToLua迁移到XLua,我踩过的那些‘坑’和最佳实践