zoukankan      html  css  js  c++  java
  • 【LeetCode & 剑指offer刷题】查找与排序题14:Wiggle Sort(系列)

    【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)

    Wiggle Sort II
    Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] < nums[3]....
    Example 1:
    Input: nums = [1, 5, 1, 1, 6, 4]Output: One possible answer is [1, 4, 1, 5, 1, 6].
    Example 2:
    Input: nums = [1, 3, 2, 2, 3, 1]Output: One possible answer is [2, 3, 1, 3, 1, 2].
    Note:
    You may assume all input has valid answer.
    Follow Up:
    Can you do it in O(n) time and/or in-place with O(1) extra space?

    C++
     
    //问题:摆动排序,a[0] < a[1] > a[2] < a[3]...
    //??没看懂,以后再看
    //方法二:利用快排中一步(nth_element函数)将序列分成两段,以中值为枢轴,从各段段首(或段尾)开始选数
    //思路解析:假设排序后为a1 a2...an mid b1 b2...bn,则组织为a1 b1 a2 b2...
    //此法时间复杂度为O(n),如果没有O(1)的空间复杂度,比较简单,正是这个限制增加了复杂度
    class Solution {
    public:
        void wiggleSort(vector<int>& nums) {
            int m = nums.size();
            auto mptr = nums.begin() + (m-1)/2;
            nth_element(nums.begin(), mptr, nums.end());
            int median = *mptr;
            int i = 1;   // position for the larger values: start with first odd index
            int j = ((m - 1) & 1) ? m - 2 : m - 1;  // position for the smaller values: start with last even index
            for (int l = 0; l < m; ++l) {
                if (nums[l] > median) {  // fill the large element
                    if (l <= i && (l & 1)) continue;       // skip the elements which are  already checked: 1, 3, 5, ..., i
                    swap(nums[l--], nums[i]);
                    i += 2;
                } else if (nums[l] < median) {  // fill the smaller element
                    if (l >= j && (l & 1) == 0) continue;     // skip the elements whcih are checked: j, j + 2, ..., lastEvenIndex
                    swap(nums[l--], nums[j]);
                    j -= 2;
                }
           }
        }
    };
    //方法一:排序后,分成两段,从各段末尾依次取数(可以避免相等数弄在一起)
    //不过此法的时间复杂度为O(nlogn),空间复杂度为O(n),不满足题意
    //思路解析:假设排序后为a1 a2...an b1 b2...bn,则组织为an bn an-1 bn-1...
    class Solution
    {
    public:
        void wiggleSort(vector<int>& a)
        {
            int n = a.size();
            sort(a.begin(),a.end());
            if(n<=2) return; //小于两个元素时,直接退出
          
            vector<int> temp = a; 
            int i = 0, j=(n-1)/2, k=n-1; //i用来遍历a, j用来遍历temp第一段(从末尾开始),k用来遍历第二段。
            for(i = 0; i < n; i++)
            {
                a[i] = (i&1)? temp[k--]:temp[j--];//如果i为奇数,取第二段的数(较大),如果为偶数,取第一段的数(较小)
                //注:当n为奇数时,两段长度不等,第一段比第二段多1,但是上述等式可以保证最后一个数a[n-1]选择temp[0]
            }
        }
    };
    /*
    //摆动排序,a[0] < a[1] > a[2] < a[3]...
    //要得到O(n)时间复杂度,O(1)空间复杂度,可以借鉴wiggle sort I(a[0] <= a[1] >= a[2] <= a[3]...)中的思路
    //i为奇数时,a[i]>a[i-1], 偶数时,a[i]<a[i-1], 根据这一规律,遍历整个序列,不符合则交换
    //测试结果表明,对于序列中有多个连续相等数时,此方法不行,因为按照交换策略,相等的数会交换,但是交换后并不会满足
    //i为奇数时,a[i]>a[i-1], 偶数时,a[i]<a[i-1]的规律,而是仍然相等。
    class Solution
    {
    public:
        void wiggleSort(vector<int>& a)
        {
            int n = a.size();
            if(n <= 1) return; //元素个数少于1个时,退出
           
            for(int i = 1; i < n; i++)
            {
                if((i%2 == 1 && a[i]<=a[i-1]) || (i%2 == 0 && a[i]>=a[i-1]))
                {
                    swap(a[i], a[i-1]);//如果不符合摆动规律则交换
                }
            }
        }
    };
    */
     
    Wiggle Sort I
    Given an unsorted array nums, reorder it in-place such that nums[0] <= nums[1] >= nums[2] <= nums[3]....
    For example, given nums = [3, 5, 2, 1, 6, 4], one possible answer is [1, 6, 2, 5, 3, 4].
     
    这道题让我们求摆动排序,跟Wiggle Sort II相比起来,这道题的条件宽松很多,只因为多了一个等号。由于等号的存在,当数组中有重复数字存在的情况时,也很容易满足题目的要求。这道题我们先来看一种时间复杂度为O(nlgn)的方法,思路是先给数组排个序,然后我们只要每次把第三个数和第二个数调换个位置,第五个数和第四个数调换个位置,以此类推直至数组末尾,这样我们就能完成摆动排序了,参见代码如下:
     
    //解法一:
    // Time Complexity O(nlgn)
    class Solution {
    public:
        void wiggleSort(vector<int> &nums) {
            sort(nums.begin(), nums.end());
            if (nums.size() <= 2) return;
            for (int i = 2; i < nums.size(); i += 2) {
                swap(nums[i], nums[i - 1]);
            }
        }
    };
     
    这道题还有一种O(n)的解法,根据题目要求的nums[0] <= nums[1] >= nums[2] <= nums[3]....,我们可以总结出如下规律:
    当i为奇数时,nums[i] >= nums[i - 1]
    当i为偶数时,nums[i] <= nums[i - 1]
    那么我们只要对每个数字,根据其奇偶性,跟其对应的条件比较,如果不符合就和前面的数交换位置即可,参见代码如下:
     
    //解法二:
    // Time Complexity O(n)
    class Solution {
    public:
        void wiggleSort(vector<int> &nums) {
            if (nums.size() <= 1) return;
            for (int i = 1; i < nums.size(); ++i) {
                if ((i % 2 == 1 && nums[i] < nums[i - 1]) || (i % 2 == 0 && nums[i] > nums[i - 1])) {
                    swap(nums[i], nums[i - 1]);
                }
            }
        }
    };
  • 相关阅读:
    el-input 标签中密码的显示和隐藏
    java 使用RedisTemplate实现Redis事务
    mac 安装 Java 环境
    Snowflake 分布式UUID
    lsof 查看端口使用时刻
    nginx.pid" failed (2: No such file or directory)
    解决Redis之MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist
    Linux环境下 Jna 解决so依赖文件not found
    Ubuntu mysql 在线安装
    Linux中为什么执行自己的程序要在前面加./
  • 原文地址:https://www.cnblogs.com/wikiwen/p/10225971.html
Copyright © 2011-2022 走看看