AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

LeetCode 324. Wiggle Sort II    原题链接    中等

作者: 作者的头像   yxc ,  2018-06-26 23:59:00 ,  所有人可见 ,  阅读 2734


4


4

题目描述

给定一个无序数组nums,请调整它的顺序,使得nums[0] < nums[1] > nums[2] < nums[3] ...。

注意: 数据保证一定存在答案。

进一步: 能否只使用 $O(n)$ 的时间,以及额外 $O(1)$ 的空间。

样例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)$ 的时间复杂度内求出第 $k$ 大数。
我们先用快速选择算法求出中位数mid,C++中可以调用 nth_element()函数。

将所有数分成三种:小于mid的数、等于mid的数和大于mid的数。
然后对数组排序,使得大于mid的数在最前面,等于mid的数在中间,小于mid的数在最后面。
这一步可以直接利用三数排序,三数排序算法可以参考LeetCode 75. Sort Colors。

然后我们将排好序的数组重排,将前半段依次放到奇数位置上,将后半段依次放到偶数位置上。此时就会有:
nums[0] < nums[1] > nums[2] < nums[3] ...

这一步重排我们可以在三数排序时做,只需在排序时做一个数组下标映射即可:
i => (1 + 2 * i) % (n | 1)
该映射可以将数组前一半映射到奇数位置上,数组后一半映射到偶数位置上。

时间复杂度分析:快速选择算法的期望运行时间是 $O(n)$,额外空间是 $O(logn)$(算法需要递归,期望递归 $logn$ 层)。三数排序算法的时间复杂度是 $O(n)$,额外空间复杂度是 $O(1)$。所以总时间复杂度是 $O(n)$,额外空间的复杂度是 $O(logn)$。题目中要求只使用额外 $O(1)$ 的空间,目前还没想到比较好的做法。有想法的同学可以在评论区交流 ^^。

C++ 代码

class Solution {
public:
    void wiggleSort(vector<int>& nums) {
        int n = nums.size();
        auto midptr = nums.begin() + n / 2;
        nth_element(nums.begin(), midptr, nums.end());
        int mid = *midptr;

        #define A(i) nums[(1 + 2 * i) % (n | 1)]

        int i = 0, j = 0, k = n - 1;
        while (j <= k)
            if (A(j) > mid)
                swap(A(i ++ ), A(j ++ ));
            else if (A(j) < mid)
                swap(A(j), A(k -- ));
            else
                j ++ ;
    }
};

6 评论


用户头像
Ron.W   2021-09-18 15:21         踩      回复

求大神讲解:这个映射如何保证不会重复呢 j是线性的 但是这个映射是取余操作 为什么可以直接操作在A的域?

用户头像
Ron.W   2021-09-18 17:13         踩      回复

https://leetcode.com/problems/wiggle-sort-ii/discuss/77677/O(n)%2BO(1)-after-median-Virtual-Indexing 详解


用户头像
三年后必进FLAG   2021-06-02 18:47         踩      回复

y总 快速选择算法的期望应该是$O(N)$吧?


用户头像
greg666   2019-04-08 14:41         踩      回复

i => (1 + 2 * i) % (n | 1) 是怎么想出来的?

用户头像
yxc   2019-04-08 19:34         踩      回复

参考leetcode题解里的,估计是作者凑出来的。

用户头像
Stella-W   2020-04-16 17:32    回复了 yxc 的评论         踩      回复

这也行


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息