旋转数组
第一次尝试
思路
数组右移动K个位置,可以划分为数组移动K次,每次移动一位,如果数组移动一位的话,只需要将最后一个放到开头,剩下的后移一位就行
代码
class Solution {
public void rotate(int[] nums, int k) {
for (int i = 0; i < k; i++) {
rightMove(nums);
}
}
// 右移一位
public void rightMove(int[] nums) {
int end = nums[nums.length - 1];
for (int i = 0; i < nums.length - 1; i++) {
nums[nums.length - 1 - i] = nums[nums.length - 2 - i];
}
nums[0] = end;
}
}
提交结果
小结
每次移动一位速度实在太慢,这时候想,如果可以提前计算好移动k位后的位置,一次移动到位,就不用反复移动数组了
第二次尝试
思路
使用 (数组下标+移动位数) % 数组长度 计算出数组位置,然后new出一个新数组,依次将数放到新数组计算出的位置
代码
class Solution {
public void rotate(int[] nums, int k) {
int[] ops = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
int index = (k+i)%nums.length;
System.out.println(i+":"+index);
ops[index] = nums[i];
}
// java是引用的,所以不可以直接将数组赋值过去,需要将数据拷贝到源数组上面
System.arraycopy(ops,0,nums,0,nums.length);
}
}
提交结果
小结
速度有所提升,但是还是不大,每次都要计算下标,而且重新new空间了,内存消耗增加了
第三次尝试
思路
观察上面的图可以看出,最后移动的结果,就是数组一分为二,然后将前后结果换过来,如果假设k不超过数组长度,那么分界线的下表就是k,按照求余数的方法,如果k超过数组长度,k mod 数组长度 也就是分界线下标
计算出下标,就可以拷贝,这期间需要一个临时个数组,保存后半部分数据,然后将前半部分拷贝到后半部分,临时数组数据拷贝到前半部分,这里就和连个数字交换值一样,需要借助第三个数字。
代码
class Solution {
public void rotate(int[] nums, int k) {
int middle = k % nums.length;
int[] temp = new int[middle];
System.arraycopy(nums,nums.length - middle,temp,0,middle);
System.arraycopy(nums,0,nums,middle,nums.length - middle);
System.arraycopy(temp,0,nums,0,temp.length);
}
}
提交结果
小结
惊人的发现执行用时超越100%超越,完美,相比于前两个的,内存消耗也降低了,但是,还是new了新数组,使用了新数组
第四次尝试
思路
在这个图我们可以看出,如果不使用临时数组拷贝的话,可以想到使用翻转,前部分翻转,后部分翻转,整体翻转
代码
class Solution {
public void rotate(int[] nums, int k) {
int middle = k % nums.length;
reverse(nums,0,nums.length - middle - 1);
reverse(nums,nums.length - middle,nums.length - 1);
reverse(nums,0,nums.length - 1);
}
public void reverse(int[] nums,int begin,int end) {
int ops = -1;
while (begin < end) {
ops = nums[begin];
nums[begin] = nums[end];
nums[end] = ops;
begin ++;
end --;
}
}
}
提交结果
小结
哈哈哈,效率相同,但是内存消耗变大了,似乎多了几个变量
总结
步步为营,一步一步提高效率,System.arraycopy 方法速度非常快,比一个一个赋值快多了
burybell@163.com