旋转数组

LeetCode每日一题,189. Rotate Array

先看题目描述

snaR81.png

大意就是给定一个数组 nums 和一个数字 k,让我们将数组向右旋转 k 步

算法和思路

使用额外数组

我们可以发现,将数组中的元素向右移动 k 步中,nums[0, len - k - 1] 的元素均会向右移动 k 位,而 nums[len - k, len - 1] 的元素会移动到数组首部 nums[0, k - 1] 的位置,由于元素向右移动的过程中会覆盖到原位置的元素,于是用一个额外数组存放 nums[len - k,len - 1] 的元素,然后将 nums[0, len - k - 1] 的元素向右移动 k 位,再将 nums[len - k,len - 1] 的元素放到 nums[0,k - 1] 位置即可

数组翻转

这个方法是看题解才知道的,可以实现 O(1) 的空间复杂度

该方法基于如下的事实:当我们将数组的元素向右移动 k 次后,尾部 k mod n 个元素会移动至数组头部,其余元素向后移动 k mod n 个位置。

该方法为数组的翻转:我们可以先将所有元素翻转,这样尾部的 k mod n 个元素就被移至数组头部,然后我们再翻转 [0,k mod n −1] 区间的元素和 [k mod n,n−1] 区间的元素即能得到最后的答案。

我们以 n = 7,k = 3 为例进行如下展示:

sn0UCd.png

算法源码

额外数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public void rotate(int[] nums, int k) {
int len = nums.length;
k = k % len;
if (k == 0) {
return;
}
int[] pre = new int[k];
for (int i = 0; i < k; i++) {
pre[i] = nums[len - k + i];
}
for (int i = len - 1; i >= k; i--) {
nums[i] = nums[i - k];
}
for (int i = k - 1; i >= 0; i--) {
nums[i] = pre[i];
}
}
}

数组翻转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public void rotate(int[] nums, int k) {
k %= nums.length;
reverse(nums, 0, nums.length - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, nums.length - 1);
}

public void reverse(int[] nums, int start, int end) {
while (start < end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start += 1;
end -= 1;
}
}
}