剑指Offer---面试题14:调整数组,使奇数位于偶数前


题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。


分析:

最开始思路是这样的(类似于快速排序):
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 NAMESort_Bubble_SortInsertion_SortMerge_Sort
TIME COMPLEXITYO(N^2)O(N^2)O(NlogN)
SPACE COMPLEXITYO(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)


根据面试官的刁难程度,写出不同的算法;或者首先就询问面试官,能不能有额外的辅助空间??还是必须再原数组中排序??根据面试官的具体要求,写出相对应的代码.加分析..

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值