算法 2.2.1 按奇偶排序数组 II【leetcode 922】

题目描述

给定一个非负整数数组 A, A 中一半整数是奇数,一半整数是偶数。

对数组进行排序,以便当 A[i] 为奇数时,i 也是奇数;当 A[i] 为偶数时, i 也是偶数。

要求所有奇数的相对顺序保持不变,所有偶数的相对顺序也保持不变。
如排序前为[1,2,3,4],其中奇数1排在奇数3之前,偶数2排在偶数4之前,排序后还需要保留这个顺序。
所以排序正确的答案应该为[2,1,4,3]

示例:
输入:[4,2,5,7]
输出:[4,5,2,7]
解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 都改变了相对顺序,所以都不正确。

提示:
2 <= A.length <= 20000
A.length % 2 == 0
0 <= A[i] <= 1000

数据结构

  • 数组

算法思维

  • 遍历、双指针

解题要点

  • 使用双指针控制奇数数字和偶数数字放入目标数组中的位置


解题思路


一. Comprehend 理解题意
  • 原始数组中有一半的奇数和一半的偶数,元素无序
    可以想象成是由两个线程“抢夺”形成的:
      一个线程负责将一个 奇数数组 中的元素插入到原始数组中
      另一个线程负责将一个 偶数数组 中的元素插入到原始数组中
  • 排序后的新数组必须是 偶数-奇数-偶数-奇数 交替的
    且不能改变 奇数数组 和 偶数数组 内部元素的原有顺序

二. Choose 选择数据结构与算法
用双指针遍历原始数组
  • 数据结构:数组
  • 算法思维:遍历、双指针
解题思路
  • 用奇偶两指针遍历 原数组A
  • 将奇偶指针位置上的元素交替插入 新数组B 中

三. Code 编码实现基本解法
class Solution {
    public int[] sortArrayByParityII(int[] A) {
    
        int len = A.length;
        int odd = 0;
        int even = 0;
    
        int[] B = new int[len];
        int indexB = 0;
    
        while (odd < len && even < len){
            while (A[even] % 2 != 0){
                even++;
            }
            B[indexB++] = A[even++];
    
            while (A[odd] % 2 != 1){
                odd++;
            }
            B[indexB++] = A[odd++];
        }
    
        return B;
    }
}

执行耗时:4 ms,击败了 31.62% 的Java用户
内存消耗:41.2 MB,击败了 33.78% 的Java用户

时间复杂度:O(n)
  • 奇数指针遍历一次 原数组A O(n)
  • 偶数指针遍历一次 原数组A O(n)
  • 新数组B的 n 次插入操作 O(n)

空间复杂度:O(n)
  • 新数组B 的内存空间 O(n)
  • 三个整型指针变量的内存空间 O(1)

四. Consider 思考更优解
改变算法思维:双指针的遍历对象:原始数组 => 结果数组
  • 用奇偶两指针遍历 新数组B
    奇数指针起始索引为1,步长为2
    偶数指针起始索引为0,步长为2
  • 遍历 原始数组A ,根据元素奇偶性插入 新数组B 的奇/偶索引位置

五. Code 编码实现最优解
class Solution {
    public int[] sortArrayByParityII(int[] A){

        int even = 0;
        int odd = 1;
        int[] B = new int[A.length];

        for (int a : A){
            if (a % 2 == 0){
                B[even] = a;
                even += 2;
            } else {
                B[odd] = a;
                odd += 2;
            }
        }

        return B;
    }
}

执行耗时:3 ms,击败了 78.92% 的Java用户
内存消耗:41.3 MB,击败了 30.58% 的Java用户

时间复杂度:O(n)
  • 一次 原始数组A 的遍历 O(n)
  • 一次 新数组B 的逐位插入 O(n)

空间复杂度:O(1)
  • 新数组B 的内存空间 O(n)
  • 两个整型指针变量的内存空间 O(1)

六. Change 变形与延伸

=== 待续 ===

你可能感兴趣的:(算法 2.2.1 按奇偶排序数组 II【leetcode 922】)