题目描述
给你一个数组,将数组中的元素向右轮转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]
输入: nums = [-1,-100,3,99], k = 2
输出: [3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]
方法一:临时数组
通过找规律发现数组下标为i
的元素向右移动k
位,如果超过了数组长度,该元素会移动到到下标为(i+k)%length
的位置。
class Solution {
public void rotate(int[] nums, int k) {
int length = nums.length;
int temp[] = new int[length];
for(int i=0; i<nums.length; i++){
temp[i] = nums[i];
}
for(int i=0; i<nums.length; i++){
nums[(i+k)%length] = temp[i];
}
}
}
甚至可以看成两个子数组整体的移位。
class Solution {
public void rotate(int[] nums, int k) {
k = k % nums.length;
int temp[] = new int[k];
int j = 0;
// 倒数k个元素存入临时数组中
for (int i = nums.length - k; i < nums.length; i++) {
temp[j++] = nums[i];
}
//0~k-1的元素后移k位
for (int i = nums.length - k - 1; i >= 0; i--) {
nums[i+k] = nums[i];
}
//将临时数组的中的元素存入原数组0~k
for (int i = 0; i < temp.length; i++) {
nums[i] = temp[i];
}
}
}
该方法用Python编写更简洁。
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
k %= len(nums)
nums[:] = nums[-k:] + nums[:-k]
方法二:多次翻转
通过数组翻转的方法实现,先全部翻转,再翻转前k
个,最后翻转剩余部分。
class Solution {
public void rotate(int[] nums, int k) {
int length = nums.length;
k = k %length;
reverse(nums, 0, length - 1); //先反转全部的元素
reverse(nums, 0, k - 1); //在反转前k个元素
reverse(nums, k, length - 1); //接着反转剩余的
}
//把数组中从[start, end]之间的元素两两交换
public void reverse(int[] nums, int start, int end) {
while (start < end) {
int temp = nums[start];
nums[start++] = nums[end];
nums[end--] = temp;
}
}
}
这方法快的离谱。
方法三:环形旋转
把数组首位相连,看成一个环,依次后移。
但这里要注意当数组长度是k
的整数倍时,会出现无限循环。
因此需要创建一个布尔类型数组统计每个元素是否被访问,如果被访问过,则从该元素的下一个元素开始。
class Solution {
public static void rotate(int[] nums, int k) {
int index = 0;
int hold = nums[0];
int length = nums.length;
boolean[] visited = new boolean[length];
for (int i = 0; i < length; i++) {
index = (index + k) % length;
if (visited[index]) {
//如果访问过,再次访问的话,会出现原地打转的现象,
//不能再访问当前元素了,我们直接从他的下一个元素开始
index = (index + 1) % length;
hold = nums[index];
i--;//这次不能算是有效移动,次数回退
} else {
//把当前值保存在下一个位置,保存之前要把下一个位置的
//值给记录下来
visited[index] = true;
int temp = nums[index];
nums[index] = hold;
hold = temp;
}
}
}
}