旋转数组
题目:
给定一个数组,将数组中的元素向右移动 *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]
说明:
- 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
- 要求使用空间复杂度为 O(1) 的 原地 算法。
思路(1)
暴力破解。数组每次向后挪一位,挪k次,O[kn]; 时间超出
public void rotate(int[] nums, int k) {
int temp=0;
if (nums.length<2){
}else{
//移动k次
for(int i=0;i<k;i++){
//每次向右移动一位
for(int j=nums.length-1;j>0;j--){
if(j==nums.length-1){
temp=nums[nums.length-1];
nums[nums.length-1]=nums[nums.length-2];
}else{
nums[j]=nums[j-1];
}
}
nums[0]=temp;
}
}
}
思路(2)
分成k组移动。时间复杂度O(n),空间复杂度O(k)
问题:先动的,可能会覆盖后动的;如下例:如果7可能会在3移动前覆盖3。
解决方案:用一个数组保留后k个数。int[] tempArr;
[1,2,3,4,5,6,7]
问题:length小于k ;如下例:length2小于k3;
解决方案:分成min组,min=Math.min(k,nums.length);
[1,2] //[2,1]
3
public void rotate(int[] nums, int k) {
//分k组,每组分别移动,O(n)
//数组长度小于2,移动次数等于0,直接输出
if (nums.length<2||k==0){
}else{
//temp2中保存移动前的值,temp用来交换前后值时,临时保存中间值
int temp=0,temp2=0;
//用来避免覆盖的数组,len=min(k,length)
int min=Math.min(k,nums.length);
int[] tempArr=new int[min];
//分min组
for(int i=0;i<min;i++){
//组内部,i+k*n,直到大于length
temp2=nums[i];
int jkl;
for(int j=i;j<nums.length;j=j+k){
jkl=j+k-nums.length;
if(jkl+1>0){
//当k远大于length,一直减length直到小于min
while(jkl>=nums.length) {
jkl=jkl-nums.length;
}
//每组最后一个值存在每组第一个值里面
tempArr[jkl]=temp2;
}else{
temp=nums[j+k];
nums[j+k]=temp2;
temp2=temp;
}
}
}
for(int i=0;i<min;i++){
nums[i]=tempArr[i];
}
}
}
执行用时 :3 ms, 在所有 Java 提交中击败了42.11%的用户
内存消耗 :39.8 MB, 在所有 Java 提交中击败了20.99%的用户
我可真是个弟弟。跑这么慢一定是我的注释写太多了。
思路(3)
这个思路是看LeetCode官方的,反转。首先将所有元素反转。然后反转前 k 个元素,再反转后面 n-kn−k 个元素,就能得到想要的结果。
假设 n=7n=7 且 k=3。
原始数组 : 1 2 3 4 5 6 7
反转所有数字后 : 7 6 5 4 3 2 1
反转前 k 个数字后 : 5 6 7 4 3 2 1
反转后 n-k 个数字后 : 5 6 7 1 2 3 4
public void rotate(int[] nums, int k) {
//先全部反。再反前k个,再反后k个
reversal(nums,0,nums.length-1);
//k可能远大于length
int i=k%nums.length;
reversal(nums,0,i-1);
reversal(nums,i,nums.length-1);
}
//反转数组
public void reversal(int[] nums,int start , int end){
while (start < end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
(去掉注释)
执行用时 :1 ms, 在所有 Java 提交中击败了99.62%的用户
内存消耗 :36.8 MB, 在所有 Java 提交中击败了95.45%的用户