题目描述
给定一个整数数组 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]
题目分析
仅分析空间复杂度 O(1) 的算法
环状替换
把第1个数字向后移动 k 位,然后把被取代的数字也向右移动 k 位,不断重复,最终会重新回到第一个数字的位置。
但是可能还有剩余的位置没有被移动,所以再从第2个数字开始移动。同时统计一下一共有多少数字被移动过,移动次数和数组大小相同时,说明所有数字都被移动过1次了。
时间复杂度O(n), 空间复杂度 O(1)
原地翻转
翻转3次,可以得到结果,以 nums = [1,2,3,4,5,6,7], k = 3 为例
1. 整体翻转
[7,6,5,4,3,2,1]
2. 翻转 [0, k)
[5,6,7,4,3,2,1]
3. 翻转 [k, n)
[5,6,7,1,2,3,4]
时间复杂度O(n), 空间复杂度 O(1)
Java
// 环状替换
public void rotate1(int[] nums, int k) {
int count = nums.length;
for (int i = 0; i < nums.length; i++) {
int cur = i;
int last = nums[i];
do {
int next = (cur + k) % nums.length;
int temp = nums[next];
nums[next] = last;
last = temp;
cur = next;
count--;
} while (cur != i);
if (count == 0) {
break;
}
}
}
// 原地翻转
public void rotate2(int[] nums, int k) {
int realK = k % nums.length;
reverse(nums, 0, nums.length - 1);
reverse(nums, 0, realK - 1);
reverse(nums, realK, nums.length - 1);
}
private void reverse(int[] nums, int start, int end) {
while (start < end) {
int temp = nums[end];
nums[end] = nums[start];
nums[start] = temp;
end--;
start++;
}
}
Kotlin
// 环状替换
fun rotate1(nums: IntArray, k: Int): Unit {
val realK = k % nums.size
if (realK == 0) {
return
}
var count = nums.size
var last = 0
for (i in nums.indices) {
var cur = i
last = nums[i]
do {
val next = (cur + realK) % nums.size
val temp = nums[next]
nums[next] = last
cur = next
last = temp
count--
} while (cur != i)
if (count == 0) {
break
}
}
}
// 原地翻转
fun rotate2(nums: IntArray, k: Int): Unit {
val realK = k % nums.size
if (realK == 0) {
return
}
nums.reverse()
nums.reverse(0, realK)
nums.reverse(realK, nums.size)
}