给定一个整数数组 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(1)
的 原地 算法解决这个问题吗?
提示 1
The easiest solution would use additional memory and that is perfectly fine.
提示 2
The actual trick comes when trying to solve this problem without using any additional memory. This means you need to use the original array somehow to move the elements around. Now, we can place each element in its original location and shift all the elements around it to adjust as that would be too costly and most likely will time out on larger input arrays.
提示 3
One line of thought is based on reversing the array (or parts of it) to obtain the desired result. Think about how reversal might potentially help us out by using an example.
提示 4
The other line of thought is a tad bit complicated but essentially it builds on the idea of placing each element in its original position while keeping track of the element originally in that position. Basically, at every step, we place an element in its rightful position and keep track of the element already there or the one being overwritten in an additional variable. We can't do this in one linear pass and the idea here is based on cyclic-dependencies between elements.
解法1:使用额外的数组
Java版:
class Solution {
public void rotate(int[] nums, int k) {
int n = nums.length;
k = k % n;
int[] copy = new int[n];
System.arraycopy(nums, 0, copy, 0, n);
for (int i = 0; i < n; i++) {
nums[i] = copy[(i - k + n) % n];
}
}
}
Python3版:
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
copy = nums.copy()
n = len(nums)
k %= n
for i in range(0, len(nums)):
nums[i] = copy[(i - k + n) % n]
复杂度分析
- 时间复杂度:O(n),n是 数组 nums 的长度。
- 空间复杂度:O(n),n是 数组 nums 的长度。
解法2:
将数组中的元素向右轮转 k
个位置,可以倒着遍历数组,提前把最后 k 个数保存。这样后面的数组更改值后,不影响前面的替换。
class Solution {
public void rotate(int[] nums, int k) {
int n = nums.length;
k = k % n;
int[] copy = new int[k];
System.arraycopy(nums, n - k, copy, 0, k);
for (int i = n - 1; i >= k; i--) {
nums[i] = nums[i - k];
}
System.arraycopy(copy, 0, nums, 0, k);
}
}
复杂度分析
- 时间复杂度:O(n),n是 数组 nums 的长度。
- 空间复杂度:O(k),k是输入的值。
解法3:数组翻转
当我们将数组的元素向右移动 k 次后,尾部 k mod n 个元素会移动至数组头部,其余元素向后移动 k mod n 个位置。
该方法为数组的翻转:我们可以先将所有元素翻转,这样尾部的 k mod n 个元素就被移至数组头部,然后我们再翻转 [0,k mod n − 1] 区间的元素和 [k mod n ,n−1] 区间的元素即能得到最后的答案。
我们以 n=7,k=3 为例进行如下展示:
原始数组 1 2 3 4 5 6 7
翻转所有元素 7 6 5 4 3 2 1
翻转 [0,k mod n−1] 区间的元素 5 6 7 4 3 2 1
翻转 [k mod n,n−1]区间的元素 5 6 7 1 2 3 4
先翻转所有元素,再翻转前 k 个元素,再翻转剩余元素。
Java版:
class Solution {
public void rotate(int[] nums, int k) {
int n = nums.length;
k = k % n;
reverse(nums, 0 , n -1);
reverse(nums, 0, k - 1);
reverse(nums, k, n - 1);
}
private void reverse(int[] nums, int start, int end) {
while (start < end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
}
Python3版:
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
def reverse(i: int, j: int) -> None:
while i < j:
nums[i], nums[j] = nums[j], nums[i]
i += 1
j -= 1
n = len(nums)
k %= n
reverse(0, n - 1)
reverse(0, k - 1)
reverse(k, n - 1)
复杂度分析
- 时间复杂度:O(n),其中 n 为数组的长度。每个元素被翻转两次,一共 n 个元素,因此总时间复杂度为 O(2n) = O(n)。
- 空间复杂度:O(1)。