题目描述
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: [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,-100,3,99] 和 k = 2
输出: [3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]
说明:
- 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
- 要求使用空间复杂度为 O(1) 的原地算法。
分析
按照题目说明,要求空间复杂度为O(1),并且这题有三种以上的解法。
- 让数组插入到第一个数组之前。但这样空间复杂度就不是O(1)了。
这是错误的,超时了。不过能够得到正确答案。
class Solution {
public void rotate(int[] nums, int k) {
int n = nums.length;
while(k != 0){
int temp = nums[n-1];
nums[n-1] = 0;
for(int i = n-2; i > -1 ; i--) {
int temp1 = nums[i];
nums[i+1] = temp1;
nums[i] = 0;
}
nums[0] = temp;
k--;
}
}
}
解法1
借助O(n)的空间解法。再利用(i + k) % n = 旋转后的位置
,可以将原有数组中的数据复制到新数组中。
例如:
3元素在数组中的2位置上,(2+3) % 7 = 5
5元素在数组中的4位置上,(4+3) % 7 = 0
6元素在数组中的5位置上,(5+3) % 7 = 1
7元素在数组中的6位置上,(6+3) % 7 = 2
根据以上可以推断出,诸如将一个数组向右偏移或者旋转多少步等之类的题目,可以通过(元素位置+偏移或旋转步数) 模与 数组长度
可以得到偏移或者旋转之后的元素位置
。
这是代码最少的方法了,不过因为leetcode对函数的类型是void,没有返回值,符合题目要求,不符合oj运行。
public int[] rotate(int[] nums, int k) {
k = k % nums.length;
int[] result = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
result[(i + k) % nums.length] = nums[i];
}
return result;
}
解法2
依旧可以利用(i+k)%n
等于新i
的思路,不过这次是每次调换一个元素,后一个元素的调换基于上一个的位置。
例如:让数组[1,2,3,4,5,6,7]
向右旋转1,可以按照以下步骤来:
public void rotate2(int[] nums, int k) {
if (nums.length == 0 || (k %= nums.length) == 0) {
return;
}
int length = nums.length;
int start = 0;
int i = 0;
int cur = nums[i];
int cnt = 0;
while (cnt++ < length) {
i = (i + k) % length;
int t = nums[i];
nums[i] = cur;
if (i == start) {
++start;
++i;
cur = nums[i];
} else {
cur = t;
}
}
}