《剑指offer》刷题——【高质量的代码】面试题21:调整数组顺序是奇数位于偶数前面(java实现)

本文介绍了一种常见的数组排序问题,即调整数组中数字的顺序,使所有奇数位于数组的前半部分,所有偶数位于后半部分。通过四种不同方法进行分析和代码实现,包括O(n^2)的遍历法、O(nlogn)的双指针法、可扩展解法以及保持奇偶相对位置不变的插入排序法。

一、题目描述

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部
分,所有的偶数位于数组的后半部分。

二、题目分析

方法一:从头遍历 O(n^2)

  • 从头扫描数组,每碰到一个偶数,取出这个数字,并把位于这个数字后面的所有数字往前挪动一位;
  • 挪完之后,数组末尾空位,把取出的偶数放在空位上
  • 每碰到一个偶数需要移动O(n)个数字
  • 总时间复杂度:O(n^2)

方法二:双指针 O(nlogn) ——未考虑奇数间、偶数间相对位置不变【类似快排】

  • 双指针:初始化分别指向数组的首尾元素,一个从头至尾移动,一个从尾至头移动
  • 第一个指针向后移动,直到找到第一个偶数;
  • 然后第二个指针向前移动,直到找到第一个奇数;
  • 此时交换两个数字;
  • 重复上述操作,直至两指针相遇
  • 两个指针相遇之前,第一个指针总是位于第二个之前

在这里插入图片描述

方法三、可扩展解法

  • 为提高代码的可重用性,我们将代码解耦:

    • 判断数字是不是符合标准
    • 拆分数组,即将元素按照规定方式放置
  • 可解决类似问题,只需新定义一个判断标准函数

    • 把数组中的数按照大小分为两部分,所有负数都在非负数的前面
    • 把数组中的数分为两部分,能被3整除的数都在不能被3整除的数的前面

方法四、考虑奇数间、偶数间相对位置不变O(n^2)——【类似插入排序】

  • 遍历每一个元素
  • 若当前遍历的元素为奇数,则向前遍历交换
  • 直到当前奇数插入到正确的位置
  • 继续遍历数组元素
  • 直到整个数组遍历完成

三、代码实现

方法二:未考虑奇数间、偶数间相对位置不变

public class Solution {
    /**
    * 调整数组顺序是奇数位于偶数前面
    */
    public void reOrderArray(int [] array) {
         
        //若数组不存在或为空
        if(array==null || array.length==0){
            return;
        }
         
        int start = 0; //头指针
        int end = array.length-1; //尾指针
         
        while(start < end){
             
            //向后移动头指针,直到它指向偶数
            while(start<end && (array[start] & 0x1)!=0){
                start++;
            }
             
            //向前移动尾指针,直到它指向奇数
            while(start<end && (array[end] & 0x1)==0){
                end--;
            }
             
            //交换头指针指向的偶数 与尾指针指向的奇数 的位置
            if(start < end){
                int temp = array[start];
                array[start] = array[end];
                array[end] = temp;
            }
        }  
    }
}

运行结果:
在这里插入图片描述

方法三、可扩展解法

public class Solution {
    /**
    * 调整数组顺序是奇数位于偶数前面
    */
    public void reOrderArray(int [] array) {
         
        //若数组不存在或为空
        if(array==null || array.length==0){
            return;
        }
         
        int start = 0; //头指针
        int end = array.length-1; //尾指针
         
        while(start < end){
             
            //向后移动头指针,直到它指向偶数
            while(start<end && !isEven(array[start])){
                start++;
            }
             
            //向前移动尾指针,直到它指向奇数
            while(start<end && isEven(array[end])){
                end--;
            }
             
            //交换头指针指向的偶数 与尾指针指向的奇数 的位置
            if(start < end){
                int temp = array[start];
                array[start] = array[end];
                array[end] = temp;
            }
        }  
    }
    
    /**
    *判断是否为偶数
    */
    public boolean isEven(int n){
        return (n & 0x1)==0;
    }
}

方法四:考虑奇数间、偶数间相对位置不变

public class Solution {
    /**
    *插入排序
    */
    public void reOrderArray(int [] array) {
        int count = 0;//记录已经摆好位置的奇数的个数
        int len = array.length-1; 
        //遍历数组中的每一个元素
        for (int i = 0; i <= len; i++) {
            //判断当前遍历元素是否为奇数
            if(array[i]%2==1){
                int j = i; //记录当前遍历元素
                //若找到一个奇数,则向前遍历,与前面的偶数依次交换位置,直到将此奇数插入到上一次找到的奇数的末尾
                while(j>count){
                    int temp = array[j];
                    array[j] = array[j-1];
                    array[j-1] = temp;
                    j--;
                }
                count++;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值