LeetCode探索(42):324-摆动排序II

152 阅读1分钟

「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战」。

题目

给你一个整数数组 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) 额外空间来实现吗?

思考

我们不难发现,本题与 摆动序列 类似。本题难度中等。在本题中,我们需要对给出的整数数组进行操作,使得返回的数组满足一小一大交替分布的特点,这也就是摆动排序的过程。

由于数组是一小一大交替分布的,那么我们可以将原数组进行排序,然后分为两个子数组,再逐一各自取出数组的元素,将两个数组进行穿插分布。考虑到数组元素可能有相同数值,比如对于数组[1, 2, 2, 3],返回结果仍为[1, 2, 2, 3],我们可以将子数组反序后再穿插分布。

解答

方法一:排序

var wiggleSort = function(nums) {
  // 排序
  nums.sort((a, b) => a - b)
  // 分组、反序
  let arr1 = nums.slice(0, Math.ceil(nums.length / 2)).reverse()
  let arr2 = nums.slice(Math.ceil(nums.length / 2)).reverse()
  // 原地修改nums数组
  for (let i = 0; i < nums.length; i++) {
    nums[i] = i % 2 === 0 ? arr1.shift() : arr2.shift()
  }
  return nums
}
// 执行用时:932 ms, 在所有 JavaScript 提交中击败了5.05%的用户
// 内存消耗:45.9 MB, 在所有 JavaScript 提交中击败了17.17%的用户

优化

var wiggleSort = function(nums) {
  let tmp = nums.slice().sort((a, b) => a - b)
  // 获取中位数索引mid
  let r = nums.length, mid = Math.floor((nums.length + 1) / 2)
  for(l = 0; l < nums.length; l++) {
    nums[l] = l % 2 === 0 ? tmp[--mid] : tmp[--r]
  }
  return nums
}
// 执行用时:84 ms, 在所有 JavaScript 提交中击败了95.96%的用户
// 内存消耗:46.1 MB, 在所有 JavaScript 提交中击败了9.09%的用户

复杂度分析

  • 时间复杂度:O(NlogN),需要对数组进行排序。
  • 空间复杂度:O(N),存储数组。

参考