转载请注明出处 http://blog.csdn.net/qq_31715429/article/details/80272086
本文出自:猴菇先生的博客
给定一个数组,将数组中的元素向右移动 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) 的原地算法。
1.首先最容易想到的:
class Solution {
public void rotate(int[] nums, int k) {
k = k % nums.length;//取余是为了旋转好几圈的情况
if (k == 0) {
return;
}
while (k > 0) {
int temp = nums[nums.length - 1];
for (int i = nums.length - 1; i > 0; i--) {
nums[i] = nums[i - 1];
}
nums[0] = temp;
k--;
}
}
}
两层循环,第一层while相当于一步一步往右移,移了几次;第二层for相当于把数组的每个元素挨个移。for里倒序循环,从倒数第二位起依次赋值给前一位,用temp变量存储最末位的值赋给第0位。
这也是我能唯一想到的解法,但是这个解法运行后消耗了130ms。。
2.这个是别人的答案,运行只需要1ms。。
public class Solution {
public void rotate(int[] nums, int k) {
if(nums == null || nums.length == 0 || k % nums.length == 0)
return;
int turns = k % nums.length;
int middle = nums.length - turns;
reverse(nums, 0, middle-1); // reverse left part
reverse(nums, middle, nums.length-1); // reverse right part
reverse(nums, 0, nums.length-1); // reverse whole part
}
public void reverse(int[] arr, int s, int e) {
while(s < e) {
int temp = arr[s];
arr[s] = arr[e];
arr[e] = temp;
s++;
e--;
}
}
}
大体意思好像是翻转翻转再翻转,反正我是没看懂。。
3.最最粗暴的,执行0ms什么鬼
class Solution {
public void rotate(int[] nums, int k) {
int[] num1 = new int[nums.length];
k = k % nums.length;
System.arraycopy(nums, nums.length - k, num1, 0, k);
System.arraycopy(nums, 0, num1, k, nums.length - k);
System.arraycopy(num1, 0, nums, 0, nums.length);
}
}
旋转数组说白了就是把第k位的左右两边掉个个,比如从[1,2,3,4,5] -> [4,5,1,2,3],往右移2位就是把4,5放到前面,1,2,3放到后面。
System.arraycopy()用来实现数组之间的复制
/**
* src:源数组
* srcPos:源数组要复制的起始位置
* dest:目的数组
* destPos:目的数组放置的起始位置
* length:复制的长度
*/
public static void (Object src, int srcPos, Object dest,
int destPos, int length)
用到这里刚好合适:先把nums的k位往后的后半段copy到nums1的前半段,再把nums的k位往前的前半段copy到nums1的后半段,再整个吧nums1复制给nums。
不得不佩服啊,LeetCode刷题任重而道远。