Leetcode:324. 摆动排序 II

Leetcode:324. 摆动排序 II

题目描述

给定一个无序的数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]... 的顺序。

示例 1:

输入: nums = [1, 5, 1, 1, 6, 4]
输出: 一个可能的答案是 [1, 4, 1, 5, 1, 6]

示例 2:

输入: nums = [1, 3, 2, 2, 3, 1]
输出: 一个可能的答案是 [2, 3, 1, 3, 1, 2]

说明:

你可以假设所有输入都会得到有效的结果。

进阶:

你能用 O(n) 时间复杂度和 / 或原地 O(1) 额外空间来实现吗?

思路

思路1

直接使用排序加取后一半位置进行插入到合适的位置,需要注意需要新建一个前半排序和后半排序后的空间,不然由于交换不能到合适的位置(或者用一个map指示排序后每个元素应该在的位置),同时还需要注意最中间的元素等于(nums.length + 1) /2的情况,所以需要能够前后排序空间都逆序,使其中间元素不在一起即在排序时不产生等号

思路2

不使用排序而直接使用三partition将数组形成小于中位数的数+中数+大于中位数的数,然后利用两个数组(中间位置之前和之后的数组)逆序,最后根据两个数组得到最后的结果

思路3

将两个数组换位虚地址

代码

代码1

class Solution {
    public void wiggleSort(int[] nums) {
        if (nums == null || nums.length == 0){
            return;
        }
        Arrays.sort(nums);
        int mid = (nums.length + 1) / 2;
        reverse(nums, 0, mid - 1);
        reverse(nums, mid, nums.length - 1);
        int[] smallNums = new int[mid];
        int[] bigNums = new int[nums.length - mid];
        for(int i = 0; i < nums.length; i++){
            if (i <= mid - 1){
                smallNums[i] = nums[i];
            }else{
                bigNums[i - mid] = nums[i];
            }
        }
        for(int i = 0; i < nums.length; i++){
            if (i % 2 == 0){
                nums[i] = smallNums[i / 2];
            }else{
                nums[i] = bigNums[i / 2];
            }
        }
    }
    
    private void reverse(int[] nums,int start,int end){
        while (start < end){
            int temp = nums[start];
            nums[start++] = nums[end];
            nums[end--] = temp;
        }
    }
    
}

代码2

class Solution {
    public void wiggleSort(int[] nums) {
        if (nums == null || nums.length == 0 || nums.length == 1){
            return;
        }
        int mid = (nums.length + 1) / 2;
        if (nums.length > 1){
            quickSelect(nums, 0, nums.length - 1, mid, false);
        }
        int midNum = nums[mid];
        int midIndex = 0, k = nums.length - 1, iterIndex =0;
        while (midIndex < k){
            if (nums[midIndex] > midNum){
                swap(nums, midIndex, k);
                k --;
            }else if(nums[midIndex] < midNum){
                swap(nums, midIndex, iterIndex);
                midIndex++;
                iterIndex++;
            }else{
                midIndex++;
            }
        }
        int[] smallNums = new int[mid];
        int[] bigNums = new int[nums.length - mid];
        for(int i = 0; i < nums.length; i++){
            if (i < mid){
                smallNums[i] = nums[mid - 1 - i];
            }else{
                bigNums[i - mid] = nums[nums.length - 1 - (i - mid)];
            }
        }
        for(int i = 0; i < nums.length; i++){
            if (i % 2 == 0){
                nums[i] =  smallNums[i / 2];
            }else{
                nums[i] = bigNums[i / 2];
            }
        }
    }
    
    private void quickSelect(int[] nums,int start,int end,int k, boolean reverse){
        int getIndex = getPartition(nums, start, end, reverse);
        while (getIndex != k){
            if (getIndex > k){
                getIndex = getPartition(nums, start, getIndex - 1, reverse);
            }
            if (getIndex < k){
                getIndex = getPartition(nums, getIndex + 1, end, reverse);
            }
        }
    }
    
    private int getPartition(int[] nums, int start, int end, boolean reverse){
        int getNum = nums[start];
        int getIndex = start;
        swap(nums, start, end);
        for(int i = start; i < end; i++){
            if ((!reverse && nums[i] < getNum) || (reverse && nums[i] > getNum)){
                swap(nums, getIndex++, i);
            }
        }
        swap(nums, getIndex, end);
        return getIndex;
    }
    
    
    private void swap(int[] nums, int i, int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
    
}

复杂度分析

思路1时间复杂度

$O(nlogn)$考虑平均情况

思路1空间复杂度

$O(n)$

思路2时间复杂度

$O(n)$考虑平均情况

思路2空间复杂度

$O(n)$

思路3时间复杂度

$O(n)$考虑平均情况

思路3空间复杂度

$O(1)$

参考文献


文章作者: 小风雷
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小风雷 !
评论
 上一篇
Leetcode:162. 寻找峰值 Leetcode:162. 寻找峰值
Leetcode:162. 寻找峰值题目描述峰值元素是指其值大于左右相邻值的元素。 给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。 数组可能包含多个峰值,在这种情况下,返回任何一个峰
2020-04-17
下一篇 
Leetcode:179. 最大数 Leetcode:179. 最大数
Leetcode:179. 最大数题目描述给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。 示例 1:输入: [10,2] 输出: 210 示例 2:输入: [3,30,34,5,9] 输出: 9534330 说明:输出结
2020-04-16
  目录