有一类问题是,将数组进行整体平移,例如整体向左或向右平移3个长度,类似于这类问题的解决方案很多,下面就来尝试使用Java语言给出三种解决方法,设想问题是将一个数组整体向右平移k个单位,即若平移前数组为{1,2,3,4,5,6,7},平移3个长度后数组为{5,6,7,1,2,3,4}。
一般,最朴素的方法是先创建一个新数组,然后按规律将数组一一赋值即可。如下代码所示:
/**
* 最朴素的算法,开辟另一个数字,拷贝进去就是了
* @param a 输入数组
* @param k 移动步数
* 时间复杂度 O(N)
* 空间复杂度 O(N)
*/
public static void rotate1(int[] a,int k) {
int[] b = new int[a.length];
for(int i=0;i<k;i++) {
b[i]=a[a.length-k+i];
}
for(int j=0;j<a.length-k;j++) {
b[j+k]=a[j];
}
System.arraycopy(b, 0, a, 0, a.length);
}
这种方法的时间复杂度为O(N),空间复杂度也为O(N),也是我们最常想到的方法。
回想起我之前学习的冒泡排序算法的思想,感觉这问题有点像,例如5,6,7依次向上冒泡,1,2,3,4依次沉到底部,因此,我们可以借助冒泡排序的思想来解决这个问题。如下代码所示:
/**
* 想到冒泡排序算法的思想
* @param a 输入数组
* @param k 移动步数
* 时间复杂度 O(N*k)
* 空间复杂度 O(1)
*/
public static void rotate2(int[] a,int k) {
for(int i=0;i<k;i++) {
for(int j=a.length-k+i;j>i;j--) {
int tmp=a[j];
a[j]=a[j-1];
a[j-1]=tmp;
}
}
}
仔细研究变化前后的数组我们会发现,首先将数组分解成两部分,然后分别对两部分进行旋转颠倒,最后合并成大数组再旋转一次,即可完成。如下代码所示:
/**
*
* @param a 输入数组
* @param k 移动步数
* 时间复杂度 O(N)
* 空间复杂度 O(1)
*/
public static void rotate3(int[] a,int k) {
reverse(a,0,a.length-k-1);
reverse(a,a.length-k,a.length-1);
reverse(a,0,a.length-1);
}
public static void reverse(int[]a,int start,int end) {
for(int i=0;i<(end-start+1)/2;i++) {
int tmp=a[start+i];
a[start+i]=a[end-i];
a[end-i]=tmp;
}
}
原文:http://my.oschina.net/zzw922cn/blog/493154