题目链接:
题目:
Given an array, rotate the array to the right by k steps, where k is non-negative.
Example 1:
Input:[1,2,3,4,5,6,7] and k = 3
Output:[5,6,7,1,2,3,4]
Explanation: rotate 1 steps to the right:[7,1,2,3,4,5,6]
rotate 2 steps to the right:[6,7,1,2,3,4,5]
rotate 3 steps to the right:[5,6,7,1,2,3,4]
Example 2:
Input:[-1,-100,3,99] and k = 2
Output: [3,99,-1,-100] Explanation: rotate 1 steps to the right: [99,-1,-100,3] rotate 2 steps to the right: [3,99,-1,-100]Note:
- Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.
- Could you do it in-place with O(1) extra space?
题目分析:
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
Note:尝试至少三种方法,空间复杂度O(1)
解题思路:
最开始的思路,弄一个新数组,然后根据 (i+k)%len,由原本数组和新数组进行下标匹配,但是这样子的空间复杂度是O(n)。
在所有考虑思路之前,如果 k >nums.length,那么相当于 k 的有效操作是 k%nums.length,这样子可以减少操作。
思路一、那就一次就右移一位,这样子相当于数组的移动,只要空间复杂度O(1)即可,每次先把数组最后一位记下,当数组从第二个开始是前一位的值,然后第一位就用原本记下数组的最后一位。这样子的时间复杂度是 O(kn)。
思路二、把原数组划分为两个部分来看:前 n - k 个元素
和 后k个元素,
进行分开处理。然后前半部分和后半部分都进行数组反转,然后总的数组进行反转(三次反转)即可。例子:
如果
n = 7 , k = 3
,给定数组[1,2,3,4,5,6,7]
,向右旋转后的结果为[5,6,7,1,2,3,4]。
第一步:前 n-k 个元素反转----4 3 2 1,后 k 个元素进行反转-----7 6 5
第二步:总的数组进行反转-----5 6 7 1 2 3 4
思路二的难点,如果是C++的话,有自带vector的反转函数,但是Java没有,所以Java需要自己写一个数组反转函数,但这个很简单,就是不断的头尾交换,然后头尾一个++,一个--。
思路三、依旧利用 (i + k) % n 等于新 index 的思路,不过这是每次调换一个元素,后一个元素的调换基于上一个的位置。例子:
如果 n = 6,k = 2,数组[1,2,3,4,5,6].。
1 会到 3的位置---[1,2,1,4,5,6],要记录下3,
然后 3 会到 5的位置---[1,2,1,4,3,6],记录下5,
5 到 1的位置---[5,2,1,4,3,6],如果此时本来记录下1的,但是实际上这个位置是处理过了。
那么我们记录一开始的位置是 0,此时新的位置还是0,再相同处理,则会导致结果出错,因此当新和一开始的位置一样的,说明要从下一个位置再开始。
因此思路三,主要会出错的点就是上面要同时记录最原始位置,和新的位置,当两个位置相等或者不相等的时候,用不同处理。
相等时:说明新和原始位置同时往下移一位,同时记录的值是新位置的值。
不等时:记录当前新位置下的值即可。
时间复杂度是O(n)。
AC代码:(Java)
思路一:时间复杂度O(k*n),空间复杂度O(1)
class Solution {
public void rotate(int[] nums, int k) {
int len = nums.length;
k %= len;
for(int i = 0;i < k;i++)
{
int temp = nums[len-1];
for(int j = len-2;j >= 0;--j)
{
nums[j+1] = nums[j];
}
nums[0] = temp;
}
return ;
}
}
思路二:时间复杂度O(n),空间复杂度O(1)
class Solution {
public static void reverse(int[] arr, int begin, int end) {
while(begin < end)
{
int temp = arr[begin];
arr[begin++] = arr[end];
arr[end--] = temp;
}
}
public void rotate(int[] nums, int k) {
int len = nums.length;
k %= len;
reverse(nums,0,len-k-1);
reverse(nums,len-k,len-1);
reverse(nums,0,len-1);
}
}
思路三:时间复杂度O(n),空间复杂度O(1)
class Solution {
public void rotate(int[] nums, int k) {
if (nums.length < 2 || k < 1 || k % nums.length == 0) {
return;
}
int currentNum = nums[0];
int currentIndex = 0;
int newIndex = 0;
int i = 0;
while (i++ < nums.length) {
newIndex = (newIndex + k) % nums.length;
int temp = nums[newIndex];
nums[newIndex] = currentNum;
if (currentIndex == newIndex) {
currentNum = nums[++newIndex];
++currentIndex;
} else {
currentNum = temp;
}
}
}
}