问题介绍
有一类问题是,将数组进行整体平移,例如整体向左或向右平移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; } } }
这种方法的时间复杂度为O(N*k),空间复杂度为O(1),借助了冒泡排序的思想。
旋转思想
仔细研究变化前后的数组我们会发现,首先将数组分解成两部分,然后分别对两部分进行旋转颠倒,最后合并成大数组再旋转一次,即可完成。如下代码所示:
/** * * @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; } }
这种方法的时间复杂度为O(N),空间复杂度为O(1),借助了旋转的思想,比较巧妙。
时间: 2024-10-12 17:09:01