leetcode
leetcode 301 ~ 350
摆动排序 II

摆动排序 II

难度:

标签:

题目描述

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

你可以假设所有输入数组都可以得到满足题目要求的结果。

 

示例 1:

输入:nums = [1,5,1,1,6,4]
输出:[1,6,1,5,1,4]
解释:[1,4,1,5,1,6] 同样是符合题目要求的结果,可以被判题程序接受。

示例 2:

输入:nums = [1,3,2,2,3,1]
输出:[2,3,1,3,1,2]

 

提示:

  • 1 <= nums.length <= 5 * 104
  • 0 <= nums[i] <= 5000
  • 题目数据保证,对于给定的输入 nums ,总能产生满足题目要求的结果

 

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

代码结果

运行时间: 33 ms, 内存: 17.4 MB


/*
 * 思路:
 * 利用Java Stream对数组进行排序,然后按照较小部分放在偶数位置,较大部分放在奇数位置来生成新的数组。
 */
import java.util.*;
import java.util.stream.IntStream;
 
public class WiggleSortStream {
    public void wiggleSort(int[] nums) {
        int n = nums.length;
        int[] sorted = IntStream.of(nums).sorted().toArray();
        int mid = (n + 1) / 2;
        int[] temp = new int[n];
        for (int i = 0; i < mid; i++) {
            temp[i * 2] = sorted[mid - i - 1];
        }
        for (int i = mid; i < n; i++) {
            temp[(i - mid) * 2 + 1] = sorted[n - i - 1];
        }
        System.arraycopy(temp, 0, nums, 0, n);
    }
}

解释

方法:

该题解的思路是先将原数组 nums 排序,然后从排序后数组的中间位置和末尾位置交替取元素放入原数组。通过这种方式,可以使得相邻元素尽量不相等,从而满足摆动排序的要求。

时间复杂度:

O(nlogn)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在将数组排序之后选择从中间和末尾位置交替取值的方式来实现摆动排序?
排序数组后从中间和末尾交替取值可以更好地确保摆动排序的效果,即相邻元素之间的差异尽可能大。通过这种方式,较小的一半和较大的一半交替出现,从而防止相邻元素大小相近,尤其是在有重复元素的情况下。这种方法相对直观且易于实现,可以有效地避免相邻的元素值相同或相近,从而满足摆动排序的需求。
🦆
在题解中提到的方法中,如果数组的长度是奇数,中间位置的元素处理方式是否有所不同?
对于奇数长度的数组,中间位置的元素是唯一的中点元素。在题解中的方法里,中间位置元素会被首先放入结果数组的首位。然后从这个中点元素的前一个元素和数组末尾的元素开始,向前交替填充剩余位置。这种处理方式确保了所有元素都被利用,并且尽量保持摆动特性。
🦆
题解使用了额外的数组来存储排序后的结果,这是否违背了原地修改数组的要求?如果是,有没有可能实现真正的原地修改?
是的,使用额外的数组存储排序后的结果确实违背了原地修改的要求。原地修改指的是不使用额外的存储空间或者只使用常数额外空间的情况下修改数组。要实现真正的原地修改,可以考虑使用特定的排序算法(如荷兰国旗问题的三向切分快速排序来分隔元素),然后利用数组索引技巧或原地交换元素来达到摆动排序的效果,但这样的方法通常比较复杂且难以正确实现。
🦆
在使用双指针方法中,如何确保每次从中间位置和末尾取出的元素能满足摆动排序的要求,特别是在遇到重复元素时?
在使用双指针方法时,通过将数组分为两部分(较小的一半和较大的一半),并从每部分的内部末端开始交替取元素,可以最大化元素之间的差异,从而满足摆动排序。即使在遇到重复元素的情况下,由于重复元素被分散在两个不同的部分中,它们不太可能相邻放置,从而减少了重复元素相邻的可能。如果排列后的数组中重复元素聚集在一起,从每个部分的末端开始取元素同样有助于减少相邻重复元素的情况。

相关问题

颜色分类

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 0、 12 分别表示红色、白色和蓝色。

必须在不使用库内置的 sort 函数的情况下解决这个问题。

 

示例 1:

输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

示例 2:

输入:nums = [2,0,1]
输出:[0,1,2]

 

提示:

  • n == nums.length
  • 1 <= n <= 300
  • nums[i]012

 

进阶:

  • 你能想出一个仅使用常数空间的一趟扫描算法吗?

数组中的第K个最大元素

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

 

示例 1:

输入: [3,2,1,5,6,4], k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

 

提示:

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 104

摆动排序

摆动排序