这道题是Google的面试题,参照WigglySortI,本质就是一个坐标映射,只是中位数有等号,映射时候需要小心,博主第一版代码直接用Sort排序,代码击败65.8%,然后参照大牛代码,使用三路快排,速度已经提起来了。和大牛的代码不同的是,大牛采用高大上的宏函数做坐标映射,博主比较笨,理解那个映射公式花了些时间,索性就用了第一版代码的坐标映射,单独写了一个for循环。大牛代码103ms,博主代码102ms,所以坐标映射部分开销是差不多的,可见代码核心还是在三路快排(三指针)上。
总结一下:
1.问题核心还是在于坐标映射,比中位数大的放到偶数坐标,比中位数小的放到奇数坐标下,等于中位数的时候就麻烦了
2.等于中位数的情况要特别小心,中位数的数量大于n/2时无解,因为总会出现相等情况,
中位数等于n/2时,需要将中位数优先填到最左或者最优,这时n必定为偶数,入 [4, 5, 5, 6],填完之后是[4 5 5 6]还是[5 6 4 5]呢?就是说,要先填那个6,左大右小,从大向小填才能保证将可能临接的中位数隔开(否则小行的大数不在最右,大行的小数不在最左)。这就是坐标映射时候需要小心的了。
3.最后就是三路快排,将小于、等于、大于的数组排序了,下面直接上代码。
博主的两版代码:
void wiggleSort(vector<int>& nums) { const int n = nums.size(); nth_element(nums.begin(), nums.begin() + n/2, nums.end()); const int mid = nums[n/2]; int i = 0, j = 0, k = n - 1; while (j <= k){ if (nums[j] < mid){ swap(nums[j++], nums[i++]); } else if (nums[j] > mid){ swap(nums[j], nums[k--]); } else{ j++; } } vector<int> wiggly(n); j = -1; for (i = n - 1; i >= 0; --i){ j += 2; if (j >= n){ j = 0; } wiggly[j] = nums[i]; } swap(wiggly, nums); } // 第一版代码简洁些: void wiggleSort_FirstEdition(vector<int>& nums) { vector<int> wiggly(nums.size()); sort(nums.begin(), nums.end()); int j = -1; for (int i = nums.size() - 1; i >= 0; --i){ j += 2; if (j >= nums.size()){ j = 0; } wiggly[j] = nums[i]; } swap(nums, wiggly); }
大牛的代码:
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++; } }
OK,See You Next Chapter!