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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/wiggle-sort-ii

普通思路 O(nlogn):由于要满足一大一小的关系,要想快速找到一大一小的数,我们可以先对他们进行排序,在排序之后,以中位数为准,显然右边的数都比左边的数大,所以我们可以把左右两边的数交替取值合并,就能得到“交替一大一小”的关系。

但是需要注意的是,如果与中位数值相等的数有多个,那么交替插入一大一小的数的时候就需要注意了,因为有可能出现相邻的两个数相同的情况。例如 [1,1,2,2,2,2,3,3],划分为[1,1,2,2]与[2,2,3,3],如果我们按顺序交替取值,合并的结果就是[1,2,1,2,2,3,2,3]。这是因为中间数2的数量太多,而且切分后,2还是相邻太近了。所以我们要让他们相互离得远一点,切分后,各自左右翻转180度。变成[2,2,1,1] [3,3,2,2],这样,两个数组的2就离得够远了。交替取值合并的结果就是[2,3,2,3,1,2,1,2]

所以整体思路就是:1.排序 2.划分 3.翻转 4.交替取值

在切分中,如果想把右边的数组交替插入到左边的数组,我们一般把元素较多的放在左边。我们知道:

1⃣️  n/2切分,左边的个数<=右边的个数;

2⃣️  (n+1)/2切分,左边的个数>=右边的个数;

例如,切分长度为5的数组,用 1⃣️ 切分,左边有2个,右边有3个;用 2⃣️ 切分,左边有3个,右边有2个。

所以我们会选择用 2⃣️ 切割。

当然,我们们也可以把切分点定为 n/2 + (n%2)

    void wiggleSort(vector<int>& nums) {//排序sort(nums.begin(), nums.end());int n = nums.size();//切分vector<int> A, B;for (int i = 0; i < (n + 1) / 2; i++)A.push_back(nums[i]);for (int i = (n + 1) / 2; i < n; i++)B.push_back(nums[i]);//交替逆向取值for (int i = 0; i < A.size(); i++)nums[2 * i] = A[A.size() - 1 - i];for (int i = 0; i < B.size(); i++)nums[2 * i + 1] = B[B.size() - 1 - i];}

进阶思路O(n):

我们只是想得到切分后的两个数组,且右边的所有数>=左边的所有数,这个时候,我们可以用“快速选择O(n)”,找出第n/2个数,找到后,左边的数都<=nums[n/2]小,右边都>=nums[n/2]。这个时候,我们那再用“三路划分O(n)”把中位数都集中放到中间,然后再“切分”、“翻转”、“交替取值”

    void wiggleSort(vector<int>& nums) {int n=nums.size();auto mid_ptr = nums.begin()+n/2;nth_element(nums.begin(),mid_ptr,nums.end());快速选择找到中位数int mid = *mid_ptr;//三路划分,让中位数集中到中间int i=0,j=0,k=n-1;for(int j=0;j<k;){if(nums[j]<mid){swap(nums[j++],nums[i++]);}else if(nums[j]>mid){swap(nums[j],nums[k--]);}else{j++;}}if(n%2)mid_ptr++;//切分左右数组vector<int> A(nums.begin(),mid_ptr);vector<int> B(mid_ptr,nums.end());//逆向交替取值for(int i=0;i<A.size();i++){nums[2*i]=A[A.size()-1-i];}for(int i=0;i<B.size();i++){nums[2*i+1]=B[B.size()-1-i];}}

终极思路:虚拟地址法,O(1)空间复杂度:

在上面的思路中,我们划分后,元素在数组中的位置还不是最终的位置。我们总是要把他们拿下来,然后交替放到最终位置。那我们能不能找到一种方法,在划分存放元素的时候,就自动存放到最终的位置呢?

我们可以建立一个“映射”,可以理解成是一个“通道”,如图,带箭头的线可以看作是通道,如果我们把数放在“虚地址”,它就会自动通过“通道”掉落到“实地址”即最终位置。

定义映射为:

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

按照这个道理,我们可以把“虚地址”看作是划分后元素临时存放的位置,“实地址”看作是元素最终存放的位置。我们在划分数组的时候,“较大的部分放在虚地址左边,较小的部分放在虚地址右边”

    void wiggleSort(vector<int>& nums) {int n=nums.size();auto mid_ptr = nums.begin() + n/2;nth_element(nums.begin(),mid_ptr,nums.end());//找中位数int mid = *mid_ptr;//映射#define A(i) nums[(1+(i<<1)) % (n|1)]//三路划分int i=0,j=0,k=n-1;while(j<=k){if(A(j)>mid){swap(A(i),A(j));i++,j++;}else if(A(j)<mid){swap(A(k),A(j));k--;}else{j++;}}}

以上思路来自leetcode题解

摆动排序leetcode324相关推荐

  1. C++Wiggle Sort摆动排序的实现算法(附完整源码)

    C++Wiggle Sort摆动排序的实现算法 C++Wiggle Sort摆动排序的实现算法完整源码(定义,实现,main函数测试) C++Wiggle Sort摆动排序的实现算法完整源码(定义,实 ...

  2. LeetCode 280. 摆动排序

    文章目录 1. 题目 2. 解题 1. 题目 给你一个无序的数组 nums, 将该数字 原地 重排后使得 nums[0] <= nums[1] >= nums[2] <= nums[ ...

  3. 【leetcode】324.摆动排序 II (四种解法,快速排序+3way-partition等,java实现)

    324. 摆动排序 II 难度中等 给定一个无序的数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]... 的顺序. 示例 1 ...

  4. [Swift]LeetCode324. 摆动排序 II | Wiggle Sort II

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...

  5. 324. Wiggle Sort II | 324. 摆动排序 II(降序穿插)

    题目 https://leetcode.com/problems/wiggle-sort-ii/submissions/ 题解 没有一次想到正确的方法,是在 WA 的测试用例的提示下,一点一点修正,才 ...

  6. 【LeetCode 剑指offer刷题】查找与排序题14:Wiggle Sort(系列)

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) Wiggle Sort II Given an unsorted array nums, reorder it su ...

  7. LeetCode 376. 摆动序列(贪心 动态规划)

    文章目录 1. 题目 2. 解题 2.1 贪心 2.2 动态规划 1. 题目 如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列.第一个差(如果存在的话)可能是正数或负数.少于两个 ...

  8. C#LeetCode刷题-排序

    排序篇 # 题名 刷题 通过率 难度 56 合并区间 31.2% 中等 57 插入区间 30.4% 困难 75 颜色分类 48.6% 中等 147 对链表进行插入排序 50.7% 中等 148 排序链 ...

  9. leetcode 978. Longest Turbulent Subarray | 978. 最长湍流子数组(Java)

    题目 https://leetcode.com/problems/longest-turbulent-subarray/ 题解 虽然 similar questions 没列出来,但能想到之前做过的( ...

最新文章

  1. NSMutableArray 记住取不到时要进行强转
  2. 如何在TC里输出下拉列表
  3. servlet和jsp中间的交互
  4. Spring 3.1缓存抽象教程
  5. ClearCase是全球领先的软件配置管理工具
  6. Springboot 使用校验框架validation校验
  7. 【git系列】合并分支进master
  8. Flash Player 谢幕,多少程序员的“青结”时刻 | 视频
  9. php为首字母的词语,PHP提取中英文词语及数字首字母的简单示例
  10. mybatis float 小数0 不显示_卧槽!用 float 存储金额,老板说损失从工资里扣!
  11. 在团队中我的索引卡任务
  12. [VB.NET]请教一个如何对姓名进行同音字查询?
  13. 2022危险化学品经营单位主要负责人考试模拟100题及模拟考试
  14. No Route to Host from master/192.168.2.131 to master:9000 failed on socket t
  15. CCTV十集大型纪录片《华尔街》高速下载地址
  16. Python pip distribute
  17. 大数据学习笔记1.3 Linux目录操作
  18. java e_java中E表示什么意思
  19. Web开发中软件工程艺术(Web程序员请进来谈谈,特别是有大型门户网站后台开发的程序员)
  20. 汇编语言、高级语言(系统语言)、脚本语言的异同

热门文章

  1. 国内首个深度学习工程师认证标准发布
  2. AI一分钟|外媒:AI将消灭资本主义;特斯拉再遭唱空:量产存疑外加事故不断...
  3. 6月机器学习热文TOP10,精选自1400篇文章
  4. 天哪,路由器都能跑Docker了!
  5. 面试官问:消息被重复消费,怎么避免?有什么好的解决方案?
  6. 感受 lambda 之美!
  7. 14 个 Spring MVC 顶级技巧,随时用随时爽,一直用一直爽
  8. 扛住100亿次请求?我们来试一试!
  9. JVM最多支持多少个线程?
  10. 快乐学习Pandas入门篇:Pandas基础