剑指Offer #13 调整数组顺序使奇数位于偶数前面 | 图文详解

题目来源:牛客网-剑指Offer专题
题目地址:调整数组顺序使奇数位于偶数前面

题目描述

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

题目解析

对于这道题,有三种实现方式,时间复杂度分别为 O ( n 2 ) O(n^2) O ( n l o g n ) O(n logn) O ( n ) O(n) ,下面我们来逐一介绍:

方法一:
思路类似于插入排序:遍历 a r r a y array ,当遇到array[i]偶数时,就p=i+1位置开始寻找第一个奇数。如果找到了,则将array[p]移动到array[i]前面。否则,说明数组的调整已经完成,遍历停止。
1
上图是某次遇到偶数时的执行图示,供大家理解。这个算法的时间复杂度为 O ( n 2 ) O(n^2)

public class Solution {
    public void reOrderArray(int [] array) {
        int size = array.length;
        for (int i = 0; i < size; i++) {
            if (array[i] % 2 == 0) {
                int p = i + 1;
                //寻找array[i]以后的第一个奇数
                while (p < size && array[p] % 2 != 1) p++;
                if (p < size) {
                    //array[p]移动到array[i]的位置,且将保持相对位置不变
                    int t = array[p];
                    for (int j = p; j > i; j--) {
                        array[j] = array[j - 1];
                    }
                    array[i] = t;
                } else {
                    //说明已经完成了数组的调整
                    break;
                }
            }
        }
    }
}

方法二:
这个种做法的思路源于归并排序,是我参考Cyril-廖思睿博客的思路(长见识了)。

如果你学了归并排序,理解下面代码不会有任何难度,详情可以看注解(不懂留言也可 )。算法时间复杂度为 O ( n l o g n ) O(n logn)

public class Solution {
    public void reOrderArray(int [] array) {
        if (array == null || array.length < 2) {
            return ;
        }
        orderProcess(array, 0, array.length - 1);
    }
    
    public void orderProcess(int [] array, int left, int right) {
        if (left == right) {
            return ;
        }
        int mid = left + ((right - left) >> 1);
        //进行划分操作
        orderProcess(array, left, mid);
        orderProcess(array, mid + 1, right);
        //进行合并操作
        mergeOrder(array, left, mid, right);
    }
    //进行合并操作
    public void mergeOrder(int [] array, int left, int mid, int right) {
        int len = right - left + 1, pLeft = left, pRight = mid + 1, p = 0;
        //暂时存空间
        int temp[] = new int[len];
        //为了保持相对顺序不变,先放左边的奇数
        while (pLeft <= mid && array[pLeft]%2 == 1) {
            temp[p++] = array[pLeft++];
        }
        while (pRight <= right && array[pRight]%2 == 1) {
            temp[p++] = array[pRight++];
        }
        //为了保持相对顺序不变,先放左边的偶数
        while (pLeft <= mid) {
            temp[p++] = array[pLeft++];
        }
        while (pRight <= right) {
            temp[p++] = array[pRight++];
        }
        //将暂存空间中的数移回原数组中
        for (int k = 0; k < len; k++) {
        	//注意相对位置
            array[left + k] = temp[k];
        }
    }
}

方法三
这种方法是一种空间换时间的一种策略,多开一个专门用于存储的偶数的数组 e v e n s evens ,在遍历的过程中,将偶数按原来的相对顺序放到 e v e n s evens 中;而奇数也在原数组中按原来的相对顺序,进行紧凑操作(直接放到上一个奇数后面)。如下图所示:
在这里插入图片描述
最后,将偶数( e v e n s evens )接到回奇数(原数组)后面,就完成了我们的调整,时间复杂度为 O ( n ) O(n)

public class Solution {
    public void reOrderArray(int [] array) {
        int size = array.length, s1 = 0, s2 = 0;
        //专门用于存储的偶数的数组
        int [] evens = new int[size];
        for (int i = 0; i < size; i++) {
        	//筛选过程,将奇数和偶数分开
            if (array[i] % 2 == 1) {
                array[s1++] = array[i];
            } else {
                evens[s2++] = array[i];
            }
        }
        //将偶数接到奇数后面
        for (int i = 0; i < s2; i++) {
            array[s1++] = even[i];
        }
    }
}

如果本文对你有所帮助,要记得点赞哦~

发布了85 篇原创文章 · 获赞 170 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/weixin_42292229/article/details/104707858