文章前言
今天拆解 LeetCode Hot100 经典数组题:189. 轮转数组,题目要求将数组整体向右轮转 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.尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
2.你可以使用空间复杂度为 O(1) 的原地算法解决这个问题吗?
前置小知识点
当k > 数组长度时,旋转整数组长度次数等于数组还原,因此统一处理:k = k % nums.length,去除无效旋转。
二、解法一:暴力循环移位(直观易懂,大数据量超时)
思路
循环 k 次,每一轮只将数组最后一位元素取出,整体数组向后挪一位,最后把末尾元素放到数组头部。
Java 代码实现
java
class Solution {
public void rotate(int[] nums, int k) {
int n = nums.length;
k = k % n;
// 循环k次,每次右移1位
for (int i = 0; i < k; i++) {
// 保存最后一个元素
int last = nums[n - 1];
// 数组整体后移一位
for (int j = n - 1; j > 0; j--) {
nums[j] = nums[j - 1];
}
// 头部赋值
nums[0] = last;
}
}
}
复杂度分析
•时间复杂度:O(n×k),数组长度 n,循环 k 次移位,数组很长时直接超时
•空间复杂度:O(1),仅使用临时变量存储末尾值
优缺点
优点:逻辑直白,新手容易理解轮转逻辑;
缺点:效率极低,力扣大数据用例直接超时,工程基本不用。
三、解法二:临时数组辅助(空间换时间,刷题快速过题)
思路
新建一个等长临时数组,通过公式temp(i + k) % n = numsi计算每个元素旋转后的下标,全部存入临时数组,最后使用System.arraycopy将临时数组完整覆盖到原数组。
Java 代码实现
java
class Solution {
public void rotate(int[] nums, int k) {
int n = nums.length;
k = k % n;
int[] temp = new int[n];
// 填充临时数组
for (int i = 0; i < n; i++) {
temp[(i + k) % n] = nums[i];
}
// 将临时数组全部复制覆盖原数组
System.arraycopy(temp, 0, nums, 0, n);
}
}
关键知识点:System.arraycopy 数组覆盖
System.arraycopy(源数组, 源起始索引, 目标数组, 目标起始索引, 复制长度)
是 Java 底层原生数组拷贝方法,性能优于 for 循环赋值,可以直接原地修改原数组内容,适配本题void无返回值要求。
复杂度分析
•时间复杂度:O(n),仅一次遍历数组
•空间复杂度:O(n),额外开辟一个数组空间
优缺点
优点:代码简洁、一次遍历完成,通过率稳定;
缺点:不符合进阶原地算法要求,额外占用内存。
四、解法三:三次数组翻转(原地最优解,面试核心考点)
核心原理
无需额外数组,依靠自定义区间反转函数完成轮转,三步走(样例1,2,3,4,5,6,7,k=3演示)
- 整体数组反转:7,6,5,4,3,2,1
- 反转前 k 个元素:5,6,7,4,3,2,1
- 反转后半段剩余元素:5,6,7,1,2,3,4
自定义 reverse 反转工具方法
双指针实现区间原地反转,输入数组 + 左右边界,直接修改数组内容
Java 代码实现
反转函数代码
java
// 闭区间[left,right]数组反转
private void reverse(int[] nums, int left, int right) {
while (left < right) {
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
left++;
right--;
}
}
完整代码
java
class Solution {
public void rotate(int[] nums, int k) {
int len = nums.length;
k = k % len;
reverse(nums, 0, len - 1); // 整体反转
reverse(nums, 0, k - 1); // 前k位反转
reverse(nums, k, len - 1); // 后半段反转
}
// 区间反转工具函数
private void reverse(int[] nums, int left, int right) {
while (left < right) {
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
left++;
right--;
}
}
}
复杂度分析
•时间复杂度:O(n),数组每个元素仅被交换 2 次
•空间复杂度:O(1),仅临时交换变量,纯原地操作
优缺点
优点:完美满足进阶 O (1 空间要求,面试标准答案;反转函数是数组通用工具,可以复用在大量算法题;
缺点:需要理解反转逻辑,新手需要画图辅助理解。
五、三种方案横向对比表

六、核心总结
1.数组旋转预处理必做k = k % nums.length,规避超大 k 值无效运算;
2.System.arraycopy是数组覆盖赋值高效 API,注意区分数组直接赋值(只是修改引用,无法修改原数组内容);
3.双指针reverse区间反转是数组高频工具函数,必须熟练手写;
4.面试遇到数组旋转类题目,直接给出三次反转原地解法,是最优解题答案。