LeetCode 189 轮转数组

题目

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:

1
2
3
4
5
6
输入: 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:

1
2
3
4
5
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

提示:

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1
  • 0 <= k <= 105

进阶:

  • 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
  • 你可以使用空间复杂度为 O(1)原地 算法解决这个问题吗?

题解

法一:使用额外数组

这题第一个方法是新建数组,但是时间复杂度不满意,不用,就是倔,哪怕用的方法二没憋出来也不用/(ㄒoㄒ)/~~。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public void rotate(int[] nums, int k) {
int n = nums.length;
int[] newArr = new int[n];
for (int i = 0; i < n; ++i) {
newArr[(i + k) % n] = nums[i];
}
System.arraycopy(newArr, 0, nums, 0, n);
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/rotate-array/solutions/551039/xuan-zhuan-shu-zu-by-leetcode-solution-nipk/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

法二:环状替代

核心思想就是需要交换nums[x]nums[(x + k) % n],我这里出现的问题是没确定下来遍历的次数,可能是因为和群里朋友聊天了吧,下次刷题一定要专心!

力扣里确定循环次数的方法是:当从位置0开始,将第一个nums[0]nums[(0 + k) % n]交换后,令x=(0 + k) % n,然后再交换nums[x]nums[(x + k) % n],一直下去直到回到初始位置0。

这个时候会出现有些数字未遍历到的情况,那么确定遍历次数的方法为:因为当所有数字都遍历到的时候,上述过程走过a圈,并且该过程共遍历b个元素。那么an=bk,也就是说annk的公倍数,又因为第一次回到起点就结束,那么a肯定是最小的那个,也就是nk的最小公倍数lcm(n, k)。那么b就是lcm(n, k) / k\[ \frac{n}{\text{lcm}(n,k)/k}=\frac{nk}{\text{lcm}(n,k)}=\text{gcd}(n,k) \] image.png

上述分析来自力扣官方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public void rotate(int[] nums, int k) {
// 分析新旧位置的关系 indexNew = (indexOld + k) % nums.length
int n = nums.length;
k = k % n;
int count = gcd(k, n);
for (int start = 0; start < count; ++start) {
int current = start;
int prev = nums[start];
do {
int next = (current + k) % n;
int temp = nums[next];
nums[next] = prev;
prev = temp;
current = next;
} while (current != start);
}
}

public int gcd(int x, int y) {
return y > 0 ? gcd(y, x % y) : x;
}
}

时间复杂度:O(N),空间复杂度:O(1)

法三:数组翻转

这个方法需要注意到,数组元素右移k位后,尾部k % n个元素会移动到数组头部,其余元素后移k % n个位置。

那么我们可以先把数组整体翻转,这样尾部元素就移动到头部了(此时是逆序),然后再把[0, k % (n - 1)][k % (n - 1), n - 1]分别翻转即可。

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;
}
}
}

时间复杂度:O(2n) = O(n),空间复杂度:O(n)

还以为自己顿悟了,其实还是菜/(ㄒoㄒ)/~~,继续努力吧。


LeetCode 189 轮转数组
https://excelius.xyz/leetcode-189-轮转数组/
作者
Ther
发布于
2024年5月16日
许可协议