轮转数组
Rotate Array
把数组向右轮转 k 个位置,要求原地完成,尽量不使用额外数组。
在力扣中练习题目描述
给定一个整数数组 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 <= 105-231 <= nums[i] <= 231 - 10 <= k <= 105
进阶:
- 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
- 你可以使用空间复杂度为
O(1)的 原地 算法解决这个问题吗?
解题思路
主解法
三次反转 · O(1) 空间
整体反转,再分别反转前后两段
向右轮转 k 步,等价于把末尾 k 个数搬到前面。用额外数组很容易,但题目希望原地完成。
三次反转可以做到:
- 反转整个数组,末尾 k 个数跑到前面,但两段内部顺序都反了;
- 反转前 k 个数,恢复前半段的内部顺序;
- 反转剩下的 n-k 个数,恢复后半段。
自拟主例 [3,5,7,9,11,13],k=2:整体反转得 [13,11,9,7,5,3];反转前 2 个得 [11,13,9,7,5,3];反转后 4 个得 [11,13,3,5,7,9]。
分步图解
k = 2,先对 n = 6 取模;原地轮转 k = 2 步。
- k
- 2
分步图解
反转前 k 个数:11 13 9 7 5 3;前缀恢复成正向。
- k
- 2
时间 O(n),空间 O(1)。注意先做 k %= n,否则 k 大于 n 时区间会越界。
时间 O(n)空间 O(1)
易错点
- 忘记 k %= n:k 大于 n 时反转区间越界。
- 第二次反转的范围写成 [0, n-k):方向反了,前 k 个才是要恢复的段。
- 三次反转顺序颠倒:先分段反转再整体反转,得到的不是轮转结果。
- n = 0 或 k = 0 没有特判:反转空区间虽然安全,但边界要确认。
对照解法
额外数组 · 直接放置
复制一份,按 (i+k) % n 放回
时间 O(n),但需要 O(n) 额外空间;主解法三次反转满足原地要求。
最直观的做法:先把原数组复制一份,再把每个元素写到 (i + k) % n。
时间 O(n),空间 O(n)。它不容易写错,适合先验证轮转方向;如果题目允许额外空间,这也是可提交的解法。
- 1k %= n,复制原数组。
- 2i 从 0 到 n-1:nums[(i+k)%n] = copy[i]。
时间 O(n)空间 O(n)
易错点
- 取模写成 i + k:i + k 可能超过 n,下标越界。
- 直接在原数组上覆盖:还没读到的元素会被写掉。
代码与演示
主解法配有图解;对照解法用于比较思路、复杂度或实现方式。
演示输入
nums = [3,5,7,9,11,13], k = 2k = 2,先对 n = 6 取模;原地轮转 k = 2 步。
- k
- 2
查看 C++ 代码
延伸阅读
- 三次反转也常用于“翻转字符串里的单词”“循环移位”等需要原地重排的题。
- 如果要求向左轮转,把 k 换成 n-k 即可。