题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
分析:
最开始思路是这样的(类似于快速排序):
1. 整两个指针leftPos,rightPos
,一个指向数组最前端,一个指向数组最后端;
2. leftPos
向右移动,当array[leftPos]%2==0
的时候停下来,与此同时rightPos
向右移动,当array[rightPos]%2==1
的时候停下来;
3. swap(array,leftPos,rightPos);
4. 当leftPos<rightPos
条件不满足时,跳出方法,程序结束.
public void reOrderArray(int [] array) {
int leftPos=0;
int rightPos=array.length-1;
while(leftPos<rightPos){
while(array[leftPos]%2==1){
leftPos++;
}
while(array[rightPos]%2==0){
rightPos--;
}
int temp=array[rightPos];
array[rightPos]=array[leftPos];
array[leftPos]=temp;
}
}
}
但是发现这样做是不满足题目的要求,注意到题目中所要求的:”并保证奇数和奇数,偶数和偶数之间的相对位置不变“也就是要求我们所写的方法是稳定的.
回顾几种经典的排序,其中冒泡排序,直接插入排序,归并排序 是稳定的,那么我们就可以使用这三种排序的思想实现这个方法,再进一步分析:
SORT NAME | Sort_Bubble_Sort | Insertion_Sort | Merge_Sort |
---|---|---|---|
TIME COMPLEXITY | O(N^2) | O(N^2) | O(NlogN) |
SPACE COMPLEXITY | O(1) | O(1) | O(N) |
总结下来如下:冒泡排序和插入排序是”用时间换空间”,归并排序是”用空间换时间”,
所以,分别用两种思路实现如下(Bubble 略):
插入排序思路:
public void reOrderArray(int [] array) {
for(int i=1;i<array.length;i++){
int tmp=array[i];
if(tmp%2==1){
for(int j=i;j>0&&array[j-1]%2==0;j--){
int t=array[j-1];
array[j-1]=array[j];
array[j]=t;
}
}
}
}
时间复杂度:O(N^2),空间复杂度:O(1)
归并排序思路(递归方式):
public void reOrderArray(int [] array) {
int n=array.length;
int[]tmpA=new int[n];
reOrderArray(array,tmpA,0,n-1);
}
public void reOrderArray(int[]array,int[] tmpA,int leftPos,int rightEnd){
if(leftPos<rightEnd){
int center=(rightEnd+leftPos)/2;
reOrderArray(array,tmpA,leftPos,center);
reOrderArray(array,tmpA,center+1,rightEnd);
merge(array,tmpA,leftPos,center+1,rightEnd);
}
}
public void merge(int[]array,int[]tmpA,int leftPos,int rightPos,int rightEnd){
int leftEnd=rightPos-1;
int tmpPos=leftPos;
int elementNum=rightEnd-leftPos+1;
while(leftPos<=leftEnd&&array[leftPos]%2==1){
tmpA[tmpPos++]=array[leftPos++];
}
while(rightPos<=rightEnd&&array[rightPos]%2==1){
tmpA[tmpPos++]=array[rightPos++];
}
while(leftPos<=leftEnd){
tmpA[tmpPos++]=array[leftPos++];
}
while(rightPos<=rightEnd){
tmpA[tmpPos++]=array[rightPos++];
}
for(int i=0;i<elementNum;i++,rightEnd--){
array[rightEnd]=tmpA[rightEnd];
}
}
时间复杂度:O(NlonN),空间复杂度:O(N)
对上述排序比较清楚的,一看代码就知道是什么意思了,就不做赘述了.
当然,这道题目,不往经典排序的方向思考也可以,我们完全可以整一个容器,先把原数组中的奇数push进去,在把原数组中的偶数push进去,然后用新数组覆盖原有数组;
public void reOrderArray(int [] array) {
int[] tmpA=new int[array.length];
int t=0;
for(int i=0;i<array.length;i++){
if(array[i]%2==1){
tmpA[t++]=array[i];
}
}
for(int i=0;i<array.length;i++){
if(array[i]%2==0){
tmpA[t++]=array[i];
}
}
for(int i=0;i<tmpA.length;i++){
array[i]=tmpA[i];
}
}
时间复杂度:O(N),空间复杂度:O(N)
根据面试官的刁难程度,写出不同的算法;或者首先就询问面试官,能不能有额外的辅助空间??还是必须再原数组中排序??根据面试官的具体要求,写出相对应的代码.加分析..