0628-324. 摆动排序 II

93 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情

给你一个整数数组 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]

排序

首先想到的解法即为排序,然后找到满足相邻的严格大小的关系。需要观察一下什么样的数组才能满足题目的要求,可以完成最终的摆动排序。假设数组中元素的数目为 nnn,则此时我们可以得到结论数组中相同元素的数目最多不超过 n+12\left\lfloor \dfrac{n + 1}{2} \right\rfloor,我们可以用反证法来证明。当相同的元素的数目大于 n+12\left\lfloor \dfrac{n + 1}{2} \right\rfloor,此时无论如何摆放都会有相同的元素相邻,必然导致摆动排序无法完成。将数组按照从小到大进行排序后,令 x=n+12x = \left\lfloor \dfrac{n + 1}{2} \right\rfloor,此时根据前面的推论可以推测 nums[i]nums[i+x]\textit{nums}[i] \neq \textit{nums}[i+x],则一定满足 nums[i]<nums[i+x]\textit{nums}[i] < \textit{nums}[i+x]

此时我们可以利用上述关系完成数组的摆动排列。我们分两种情况来讨论:

  • nn 为偶数时:因为 nums[i]<nums[i+x]\textit{nums}[i] < \textit{nums}[i+x],所以一定满足 nums[i]<nums[i+x],nums[i1]<nums[i+x]\textit{nums}[i] < \textit{nums}[i+x], \textit{nums}[i-1] < \textit{nums}[i+x],因此我们将 nums[i+x]\textit{nums}[i+x] 插入到 nums[i]nums\textit{nums}[i] 与 \textit{nums} 之间,比如我们可以按照以下顺序进行插入:

    nums[x],nums[0],nums[x+1],nums[1],,nums[n2x],nums[n1],nums[n1x]nums[x],nums[0],nums[x+1],nums[1],⋯,nums[n−2−x],nums[n−1],nums[n−1−x]

    然后将上述序列进行反转:

    nums[n1x],nums[n1],nums[n2x],,nums[1],nums[x+1],nums[0],nums[x]nums[n−1−x],nums[n−1],nums[n−2−x],⋯,nums[1],nums[x+1],nums[0],nums[x]

    即可得到合法的摆动排序。比如序列当前序列为 [0,1,2,3,4,5][0,1,2,3,4,5],我们可以得到序列 [3,0,4,1,5,2][3,0,4,1,5,2],然后将其反转即为 [2,5,1,4,0,3][2,5,1,4,0,3]

  • nn 为奇数时:此时情况稍微复杂一些,此时我们需要证明当满足 i>0i>0 时,nums[i]<nums[i+x1]nums[i] < nums[i+x-1]。此时我们可以用反证法来证明。假设存在 ii 且满足 i>0i>0,且满足 nums[i]=nums[i+x1]\textit{nums}[i] = \textit{nums}[i+x-1] 时,则此时按照排序的规则可知 nums[i]=nums[i+1]=nums[i+2]==nums[i+x1]\textit{nums}[i] = \textit{nums}[i+1] = \textit{nums}[i+2] = \cdots = \textit{nums}[i+x-1],此时数组中一共有 xx 个相同的元素。由于这 xx 个元素不能互相相邻,按照摆动排序的规则,这 xx 个相同的元素只能放在数组的偶数位的索引中(数组索引以 00 为起始),只能放置在 0,2,4,,n10,2,4,\cdots,n-1 位置上,否则就会出现相邻元素相等,而此时由于 nums[0]\textit{nums}[0] 最小,因此它只能放置在偶数位的索引上,而数组中的偶数位的索引最多只有 xx 个,这就必然会导致矛盾,nums[0]\textit{nums}[0] 无法摆放。因此,当满足 i>0i>0 时,nums[i]nums[i+x1]nums[i] \neq nums[i+x-1],也即 nums[i]<nums[i+x1]\textit{nums}[i] < \textit{nums}[i+x-1]。根据上述的结论我们可以得到 nums[i]<nums[i+x]\textit{nums}[i] < \textit{nums}[i+x]nums[i+1]<nums[i+x]\textit{nums}[i+1] < \textit{nums}[i+x]。因此我们将 nums[i+x]\textit{nums}[i+x] 插入到 nums[i]\textit{nums}[i]nums[i+1]\textit{nums}[i+1]之间,比如我们可以按照以下顺序进行插入:

    nums[0],nums[x],nums[1],,nums[n1x],nums[n1],nums[nx]nums[0],nums[x],nums[1],⋯,nums[n−1−x],nums[n−1],nums[n−x]

    比如序列当前序列为 [0,1,2,3,4][0,1,2,3,4],我们可以返回序列 [0,3,1,4,2][0,3,1,4,2]。同理我们将上述序列进行反转后,该序列仍然为符合要求的摆动排序。

    var wiggleSort = function(nums) {
        const arr = nums.slice();
        arr.sort((a, b) => a - b);
        const n = nums.length;
        const x = Math.floor((n + 1) / 2);
        for (let i = 0, j = x - 1, k = n - 1; i < n; i += 2, j--, k--) {
            nums[i] = arr[j];
            if (i + 1 < n) {
                nums[i + 1] = arr[k];
            }
        }
    };