转载于:编程之美
问题:设计一个算法,把一个含有n个元素的数组A循环右移k位,要求时间复杂度是O(n)的。举个例子说明一下算法要达到的效果:数组中包含的元素为123456,现在要循环右移2位,则变成了561234 。
分析:对于这个问题,1:我们最常规的算法就是一步一步移位,直到移动K次,但是这样的算法复杂度是O(k*N);然后我们优化一下;既然是循环移位,那么就有个循环周期,这个循环周期就是数组大小,例如对于一个8位的数组,你移动14次跟你移动14%8=6次是一样的,所以我们可以将k进行简化k=k%N,然后再使用上面一步一步移位的算法;这样的化算法复杂度是O((k%N)*N)还是达不到我们的要求,怎么办那就要仔细分析一下移位规律了。考虑一下数组A中元素123456循环右移2位到底是怎么个情况!!!可不可以这样实现呢?将数组A分成两个部分:A[0~n-k-1] 和 A[n-k~n-1] ,将这两个部分分别翻转,然后放在一起在翻转(逆序)。具体是这样的:
(1)翻转1234:123456 ---> 432156
(2)翻转56: 432156 ---> 432165
(3)翻转432165:432165 ---> 561234
看看吧,确实完成了翻转的操作。
代码如下:
两种解法:第一个k%N简化,第二个反转
public class Array_shift
{
public static void main(String[] args) //循环移位直接是在原数组里面进行的所以会破坏原数组。
{
int a[]={1,2,3,4,5,6,7,8};
int b[]={1,2,3,4,5,6,7,8};
shieft_1(a,5);
shieft_2(b,5);
print(a);
print(b);
}
public static void shieft_1(int[] a,int k) //第一种解法 简化k=k%N。
{
int length = a.length;
k=k%(length);
while(k!=0)
{
int t = a[length-1];
for(int i=length-1;i>0;i--)
{
a[i]=a[i-1];
}
a[0]=t;
k--;
}
}
public static void shieft_2(int[] a,int k) //第二种解法,利用翻转进行操作
{
int length = a.length;
k=k%length;
reverse(a,0,length-k-1);
reverse(a,length-k,length-1);
reverse(a,0,length-1);
}
public static void reverse(int[] a,int start,int end)
{
for(int i=start;i<end;i++,end--)
{
int temp=a[end];
a[end]=a[i];
a[i]=temp;
}
}
public static void print(int[] a)
{
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+" ");
}
System.out.println();
}
}
运行结果如下:
4 5 6 7 8 1 2 3
4 5 6 7 8 1 2 3