快速排序+3 way partition+虚地址 324. 摆动排序 II

324. 摆动排序 II

给定一个无序的数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]… 的顺序。

示例 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) 额外空间来实现吗?

解题

Sort+临时数组

时间复杂度O(nlogn),空间复杂度O(n)
将数组排序;
分为前半部和后半部;
从后往前穿插给新数组;
再赋值给原始数组;

class Solution {
public:
    void wiggleSort(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int n=nums.size();
        vector<int> res;
        res.resize(n);
        int a=(n-1)/2;
        int b=n-1;
        int i=0;
        while(a>=0&&b>(n-1)/2){
            res[i++]=nums[a--];
            res[i++]=nums[b--];
        }
        if(a>=0) res[i++]=nums[a--];
        if(b>n/2) res[i++]=nums[b--];
        for(int j=0;j<n;j++) nums[j]=res[j];
    }
};

注意点:
数组分两半为 0 ~(n-1)/2: (n-1)/2+1 ~ n-1;

正序穿插可能导致尾部重复,故需要倒序穿插;

快速选择代替sort排序(时间复杂度O(n))

快速选择——找到中位数;
并且将比中位数小的放在一边,比中位数大的放在一边;
与中位数相等的放在中间;

class Solution {
public:
    void wiggleSort(vector<int>& nums) {
        int mid=find_mid(nums,0,nums.size()-1);  //找到中位数
        //threepar(nums,mid);
        insert_list(nums);
    }
private:
    void insert_list(vector<int>& nums){
        int n=nums.size();
        vector<int> res;
        res.resize(n);
        int a=(n-1)/2;
        int b=n-1;
        int i=0;
        while(a>=0&&b>(n-1)/2){
            res[i++]=nums[a--];
            res[i++]=nums[b--];
        }
        if(a>=0) res[i++]=nums[a--];
        if(b>n/2) res[i++]=nums[b--];
        for(int j=0;j<n;j++) nums[j]=res[j];
    }

    int find_mid(vector<int>& nums,int left,int right){
        if(right==left) return nums[left]; //放置下面除数为0
        int pivot_index=left+rand()%(right-left); //left和right中间的随机下标
        int p=partition(nums,pivot_index,left,right);
        int tmp=(nums.size()+1)/2;
        if(p==tmp) return nums[p];
        else if(p>tmp) return find_mid(nums,left,p-1);
        else return find_mid(nums,p+1,right);
    }
    int partition(vector<int>& nums,int pivot_index,int left,int right){
        int pivot=nums[pivot_index];
        int start_index=left;
        swap(nums[pivot_index],nums[right]);
        for(int i=left;i<right;i++)
            if(nums[i]<pivot){
                swap(nums[start_index],nums[i]);  //小的换到前面
                start_index++;
            }
        swap(nums[start_index],nums[right]);//换回来
        return start_index;
    }
};

快速选择+3way partition

C++提供的STL接口:nth_element(nums.begin(), midptr, nums.end());可以把合适的数放置midptr位置上;

nth_element()函数进行快速选择,这一函数的效果是将数组中第n小的元素放在数组的第n个位置,同时保证其左侧元素不大于自身,右侧元素不小于自身。

threepar(nums,*midptr);即可将nums进行3 way partition,将比*midptr小的数放在左边,大的放在右边;

class Solution {
public:
    void wiggleSort(vector<int>& nums) {
        auto midptr = nums.begin() + nums.size() / 2;
        nth_element(nums.begin(), midptr, nums.end());
        threepar(nums,*midptr);
        insert_list(nums);
    }
private:
    void insert_list(vector<int>& nums){
        int n=nums.size();
        vector<int> res;
        res.resize(n);
        int a=(n-1)/2;
        int b=n-1;
        int i=0;
        while(a>=0&&b>(n-1)/2){
            res[i++]=nums[a--];
            res[i++]=nums[b--];
        }
        if(a>=0) res[i++]=nums[a--];
        if(b>n/2) res[i++]=nums[b--];
        for(int j=0;j<n;j++) nums[j]=res[j];
    }

    void threepar(vector<int>& nums, int mid){
        int left=0;
        int right=nums.size()-1;
        int cur=left;
        while(cur<=right){
            if(nums[cur]<mid)   
                swap(nums[cur++],nums[left++]);
            else if(nums[cur]>mid)
                swap(nums[cur],nums[right--]);
            else cur++;
        }
    }
};

上述基础上加入虚地址

class Solution {
public:
    void wiggleSort(vector<int>& nums) {
        int n = nums.size();

        // Find a median.
        auto midptr = nums.begin() + n / 2;
        nth_element(nums.begin(), midptr, nums.end());
        int mid = *midptr;

        // Index-rewiring.
        #define A(i) nums[(1+2*(i)) % (n|1)]

        // 3-way-partition-to-wiggly in O(n) time with O(1) space.
        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++;
        }
    }
};

作者:hexcat
链接:https://leetcode-cn.com/problems/wiggle-sort-ii/solution/yi-bu-yi-bu-jiang-shi-jian-fu-za-du-cong-onlognjia/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值