LeetCode-324-摆动排序 II

文章介绍了WiggleSort(摆动排序)问题的解决方案,包括通过先排序再调整数组以及使用快速排序确定中位数的方法。在排序过程中,确保奇数位的数字大于相邻的偶数位,并处理了相同数字相邻的特殊情况。文章还提到了利用虚地址进行索引重映射的优化技巧。
摘要由CSDN通过智能技术生成

在这里插入图片描述

1、排序

考虑到在新的数组中,我们奇数位上的数字都要比相邻的偶数位上的数字大。因此我们可以先对数组进行排序,将前半部分较小的数字安排到偶数位上,将后半段较大的数字安排到奇数位上。值得注意的是,在此处我们可能会出现存在相邻数字相同的情况,因此我们还需要对数字的位置进行调整。考虑到若出现相同数字相邻的情况,一定是前半个区间的末尾和后半个区间的开头数字相同。为了避免出现这样的情况,我们可以先对前半个区间和后半个区间进行逆序操作,而后再组合成新数组。

class Solution {
public:
    void wiggleSort(vector<int> &nums) {
        vector<int> sorted{nums};
        sort(sorted.begin(), sorted.end());
        for (int i = 0; i < (sorted.size() + 1) / 2; ++i) {
            nums[2 * i] = sorted[(sorted.size() + 1) / 2 - i - 1];
        }
        for (int i = 0; i < sorted.size() / 2; ++i) {
            nums[2 * i + 1] = sorted[sorted.size() - i-1];
        }
    }
};

2、快排+虚地址

考虑到实际上我们并不需要将两个区间内的数组进行排序,实际上我们只需要获得当前数组的中位数和两个对应区间即可。为此我们可以使用快速排序来确定当前数组的中位数,而后对两个区间内的数字进行放置即可。

我们可以使用nth_element找到当前序列中的中位数,并将中位数移动到对应位置处。而后我们对于当前数组,我们从数组的两端开始相向遍历:1、若左指针指向的元素大于中位数,则交换左右指针指向的元素并将右指针左移;2、若左指针指向的元素小于中位数,则将当前元素放置左区间的有序区间内;3、若左指针指向的元素等于中位数,则右移左指针。最终我们在最当前数组进行排序即可。而后我们直接使用虚拟地址确定最终的位置。

class Solution {
public:
    void wiggleSort(vector<int>& nums) {
        auto midptr = nums.begin() + nums.size() / 2;
        nth_element(nums.begin(), midptr, nums.end());
        int mid = *midptr;
        
        // 3-way-partition
        int i = 0, j = 0, k = nums.size() - 1;
        while(j < k){
            if(nums[j] > mid){
                swap(nums[j], nums[k]);
                --k;
            }
            else if(nums[j] < mid){
                swap(nums[j], nums[i]);
                ++i;
                ++j;
            }
            else{
                ++j;
            }
        }
        
        if(nums.size() % 2) ++midptr;
        vector<int> tmp1(nums.begin(), midptr);
        vector<int> tmp2(midptr, nums.end());
        for(int i = 0; i < tmp1.size(); ++i){
            nums[2 * i] = tmp1[tmp1.size() - 1 - i];
        }
        for(int i = 0; i < tmp2.size(); ++i){
            nums[2 * i + 1] = tmp2[tmp2.size() - 1 - i];
        }
    }
};

或加上虚拟地址

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++;
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值