[Leetcode] 324. Wiggle Sort II 解题报告

该博客详细介绍了LeetCode 324题的解题报告,包括朴素的排序法和优化的就地置换法。作者首先通过排序法给出了解决方案,然后提出了在O(n)时间和O(1)额外空间内优化的就地置换法,通过特定的索引映射策略实现元素的正确放置。
摘要由CSDN通过智能技术生成

题目

Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] < nums[3]....

Example:
(1) Given nums = [1, 5, 1, 1, 6, 4], one possible answer is [1, 4, 1, 5, 1, 6]
(2) Given nums = [1, 3, 2, 2, 3, 1], 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?

思路

1、排序法:这是最朴素的做法,思路也很简单:1)对数组进行排序;2)从左到右奇数索引位置放大于中位数的数;3)从右到左在偶数索引位置放小于中位数的数,剩下的位置都放中位数。这种做法的时间复杂度是O(nlogn),空间复杂度是O(n)。可以通过Leetcode的所有测试数据,但是并不符合题目对时间复杂度和空间复杂度的要求,下面我们进行优化。

2、就地置换法:在排序法中,我们是独立的插入大于或者小于中位数的数,现在我们可以同时做,也就是在遍历数组的时候,如果当前的数大于中位数就将其从左往右放在奇数位置,如果小于中位数就将其从右往左放在偶数位置。这样还需要解决的一个问题是如何可以将他们互不干扰地放在正确的位置。举个例子:1,1,2,2,2,3这6个数:

我们可以按照这样一个顺序将数组索引拉开成这样:1,3,5,0,2,4,也就是我们可以按照这样一个顺序来遍历数组,同时维护一个低位指针用来代表奇数位置已经放到哪里,和一个高位指针来表示偶数位置已经放到哪里,这样在我们遍历数组的每一个元素的时候,就可以按照这样的方式将元素分别放高位还是低位。而要将数组按照这样的索引方式遍历,我们只需要一个映射即可,即(2 * i + 1) % (len | 1) (老实说,我也没看懂这个映射到底是怎么回事。。。)。

代码

1、排序法:

class Solution {
public:
    void wiggleSort(vector<int>& nums) {
        if (nums.size() <= 1) {
            return;
        }
        sort(nums.begin(), nums.end());
        int len = nums.size(), k = 1, high = (len % 2) ? len - 1 : len - 2, mid = nums[len / 2];
        vector<int> ans(len, mid);
        for (int i = len - 1; i >= 0 && nums[i] > mid; --i, k += 2) {
            ans[k] = nums[i];
        }
        for (int i = 0; i < len && nums[i] < mid; ++i, high -= 2) {
            ans[high] = nums[i];
        }
        nums = ans;
    }
};

2、就地置换法:

class Solution {
public:
    void wiggleSort(vector<int>& nums) {
        nth_element(nums.begin(), nums.begin()+nums.size()/2, nums.end());          // time complexity is O(n)
        int len = nums.size(), low = 0, high = len - 1, mid = nums[len/2], i = 0;  
        auto index = [=](int pos){ return (1 + pos * 2) % (len |1 ); };  
        while(i <= high) {  
            if(nums[index(i)] > mid) {
                swap(nums[index(i++)], nums[index(low++)]);
            }  
            else if(nums[index(i)] < mid) {
                swap(nums[index(i)],nums[index(high--)]);
            }  
            else {
                ++i;
            }  
        }  
    }
};

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值