输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
首先我们先分析一下题干,奇数和奇数之间,偶数和偶数之间的相对位置不变,所以要保证排序具有稳定性,而具有稳定性的排序有:插入,归并,冒泡排序,这是我们可以可以采用的排序方法。而快速排序和选择排序是不稳定的,所以不能用这两种方法来排序。
1.如果考虑不借用辅助空间的话,我们可以选择顺次移动或者相邻交换的方法,此时空间复杂度为O(1),时间复杂度较大为O(n2)。
下面我们先来看一下如何用顺次移动的方法来解决这个问题:
public class Solution {
public void reOrderArray(int [] array) {
//判断数组是否为空或是否长度为0
//数组等于null代表空指针,不指向任何对象
//长度为0的数组,指向内存中一个长度为零的数组可以进行add操作
if(array==null||array.length==0){
return;
}
int i=0,j;
while(i<array.length){
//找到数组中的第一个偶数
while(i<array.length&&!isEven(array[i])){
i++;
}
j=i+1;
//找到偶数后的第一个奇数
while(j<array.length&&isEven(array[j])){
j++;
}
//将i->j-1中的数往后移 一位i+1->j
//将原下标为j的数组元素值赋给i
if(j<array.length){
int temp = array[j];
for(int k=j-1;k>=i;k--){
array[k+1]=array[k];
}
array[i++]=temp;
}
else{
break;
}
}
}
//判断一个整数是否为偶数
public boolean isEven(int a){
if(a%2==0){
return true;
}
return false;
}
}
冒泡算法解决此问题(即相邻交换):
//对于这个算法有疑问,大家可以去看下冒泡算法的原理和相关代码
public class Solution {
public void reOrderArray(int [] array) {
if(array==null||array.length==0){
return;
}
int temp;
for(int i=0;i<array.length-1;i++){
for(int j=0;j<array.length-i-1;j++){
if(array[j]%2==0&&array[j+1]%2!=0){
temp=array[j];
array[j]=array[j+1];
array[j+1]=temp;
}
}
}
}
}
2.借助辅助空间解决此问题:借助辅助空间可以减小程序复杂度,其实是以空间换时间的方式来解决此问题。
大家最容易想到的应该就是这种方法:创建两个ArrayList,然后遍历原数组,把奇数和偶数分别存在两个链表中,然后合并赋值给原数组。这样虽然思路很清晰,可读性好,但是空间复杂度比较高。
下面我来推荐一个只用添加一个新数组就能完成此问题的方法。
时间复杂度:O(n),空间复杂度:O(n)
//这是一个典型的用空间换时间的方法
public class Solution {
public void reOrderArray(int [] array) {
if(array==null||array.length==0) return;
int oddCount=0;
int odd=0;
int[] newArr = new int[array.length];
//计算原数组中奇数的数量
for(int i=0;i<array.length;i++){
if((array[i]&1)==1){
oddCount++;
}
}
for(int j=0;j<array.length;j++){
if((array[j]&1)!=0){
//从零开始把奇数赋值到新数组中
newArr[odd++]=array[j];
}
else{
//从第oddCount个把偶数赋值到新数组中
newArr[oddCount++]=array[j];
}
}
for(int k=0;k<array.length;k++){
//最后只需要把整个新数组赋值给原数组即可
array[k]=newArr[k];
}
}
}
这个方法用时较短,且稳定,在要求时间复杂度的情况下,是一种很好的方法。