题目
给定一个整数数组 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) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
|
法二:环状替代
核心思想就是需要交换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
,也就是说an
为n
,k
的公倍数,又因为第一次回到起点就结束,那么a
肯定是最小的那个,也就是n
,k
的最小公倍数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)
\]
上述分析来自力扣官方
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) { 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ㄒ)/~~,继续努力吧。