这几天做的题有点多,所以,博客写的有点简单。
这道题是要大小数叉开,整个序列将会成为小大间隔开来,如果是我们正常情况下,肯定是选择一个中位数,然后将数组对半分开,小数放在偶数位上,大数放在奇数位上,但这就要求空间复杂度和时间复杂度都要是O(n),而题目要求不能有额外的空间消耗,因此,需要在空间复杂度上来考虑。
我们的目的是将小数放在偶数位上,大数放在奇数位上,要做到这一点我们需要两步骤,首先要确定哪些数是小数,哪些数是大数,其次是要将这些数都放在对应的位置上。
要想知道哪些数是大数,哪些数是小数,因为无法通过额外的空间进行记录,所以一种比较好的办法是找到他们的中位数,这样,在使用的时候,通过让数和中位数进行对比,就可以知道该数是小还是大。
拿出一个数和中位数进行比较,然后向指定位置上搬运,这种操作好像在二分法中用的很多,但是,不同的是,二分法中,是将数往左边和右边放,而此时我们是打算将数往奇偶位上移动,所以,要区分索引的奇偶性。而这一步我们可以借用二分法中的大小指针法去做,举个例子,我们可以把二分法中的小指针映射成奇数位,把二分法张的大指针映射成偶数位,要让一个数变成奇数,最好的办法就是: num*2+1。而让一个奇数变成偶数的方法就是:对一个奇数取余。num%奇数。
基于以上的思想,参考大神的代码,AC代码如下:
class Solution {
public:
void wiggleSort(vector<int>& nums) {
int numSize = nums.size();
if (numSize < 2) {
return ;
}
#define A(i) nums[(2*i+1)%(numSize|1)]
int midPos = 0;
nth_element(nums.begin(), nums.begin()+numSize/2, nums.end());
int mid = nums[numSize/2];
int i=0, j=0, k=numSize-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;
}
}
}
};