【数论】C018_按奇偶排序数组 I(双 list 存储 | 双端队列模拟 | 双指针)

牧云@^-^@ 提交于 2020-02-07 12:28:32

一、题目描述

Given an array A of non-negative integers, return an array consisting of all the even elements of A, 
followed by all the odd elements of A.

You may return any answer array that satisfies this condition.

Input: [3,1,2,4]
Output: [2,4,3,1]
The outputs [4,2,3,1], [2,4,1,3], and [4,2,1,3] would also be accepted.

二、题解

解题思路有三:

  • list 分别存储奇偶数
  • 双端队列存储
  • 双指针(基于交换排序)

方法一:双 list 存储

数组 AA 中所有的偶数单独存储在 evenListevenList 中,所有的奇数单独存储在 oddListoddList 中,最终,先遍历 evenListevenList,后遍历 oddListoddList

public int[] sortArrayByParity(int[] A) {

    ArrayList<Integer> evenList = new ArrayList<>();
    ArrayList<Integer> oddList = new ArrayList<>();

    for (int i = 0; i < A.length; i++) {
        if((A[i] & 1) == 0) evenList.add(A[i]);
        else                oddList.add(A[i]);
    }

    int i = 0;
    for(int even : evenList) {  // 偶数放前面
        A[i++] = even;
    }
    for(int odd : oddList) {    // 奇数放后面
        A[i++] = odd; 
    }
    return A;
}

基于以上的先将偶数存储到 evenListevenList,后将奇数存储到 oddListoddList 的思想,我们可以用一个数组 arrarr 加上一个临时指针 jj 改善一下代码:

public int[] sortArrayByParity(int[] A) {

    int[] arr = new int[A.length];
    int j = 0;  // 临时指针

    for (int i = 0; i < A.length; i++) {
      if ((A[i] & 1) == 0)  // 偶数放前面
        arr[j++] = A[i];
    }
    
    for (int i = 0; i < A.length; i++) {
      if ((A[i] & 1) == 1)  // 奇数放后面
        arr[j++] = A[i];
    }
    return arr;
  }

复杂度分析

  • 时间复杂度:O(N))O(N))NN 为 数组 AA 的元素个数。
  • 空间复杂度:O(N)O(N),前一种方法使用了两个 listlist 存储数据,但 listlist 的总个数为NN;后一种方法使用一个大小为 NN 新的数组存储数据

方法二:双端队列

将第一个数放到 listlist 中,剩余的数需判断奇偶,奇数就加到到队列的最后面,如果是偶数就加到队列的最前面。

  • 第一个数无需考虑是奇还是偶,因为它的位置不是固定不变的。
public int[] sortArrayByParity(int[] A) {

    LinkedList<Integer> list = new LinkedList<>();
    list.addLast(A[0]);

    for (int i = 1; i < A.length; i++) {
        if((A[i] & 1) == 0)  list.addFirst(A[i]); // 偶数放最前面
        else                 list.addLast(A[i]);  // 奇数放最后面
    }

    int i = 0;
    for(int n : list) {
        A[i++] = n;
    }
    return A;
}

复杂度分析

  • 时间复杂度:O(N))O(N))NN 为 数组 AA 的元素个数。
  • 空间复杂度:O(N)O(N),方法使用了一个 listlist 存储数据。

方法三:双指针

前两种方法都是从左往右遍历,逐个检查元素的奇偶性,其实可以基于交换排序的思想,从如何交换?交换的前提得是两个元素才能进行,那么从两端往中间遍历数组就必不可少了。

  • 普通的排序比较的是元素的大小。
  • 这里却比较的是奇偶性,

题目要求是的结果数列是偶奇序,且不管大小进行排列,可以让位于开头且为偶数的要与位于结尾且的奇数的进行交换。

public int[] sortArrayByParity(int[] A) {

    int Even = 0;
    int Odd = A.length - 1;

    while (Even < Odd) {
        if( (A[Even] & 1) == 1 && (A[Odd] & 1) == 0 ) {
            swap(A, Even, Odd);     // 如果Even指向奇数,Odd指向偶数,那么交换
        }
        else if( (A[Even] & 1) == 0)// 如果Even指向偶数,Even继续向右探索
            Even++;
        else if( (A[Odd] & 1) == 1) // 如果Odd指向奇数,Odd继续向左探索
            Odd--;
    }
    return A;
}
  
private static void swap(int[] A, int i, int j) {
    int t = A[i];
    A[i] = A[j];
    A[j] = t;
}

复杂度分析

  • 时间复杂度:O(N))O(N))NN 为 数组 AA 的元素个数。
  • 空间复杂度:O(1)O(1),无额外存储空间的使用。
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!