题目描述
给出一个整数数组nums,重新排列nums使得nums[0] < nums[1] > nums[2] < nums[3]…
Example:
nums = [1, 5, 1, 1, 6, 4], 一个可能的答案是[1, 4, 1, 5, 1, 6]
数据保证必定有解。
分析解答
解法I O(nlogn)时间排序+O(n)空间辅助数组解法:
对原数组排序,得到排序后的辅助数组tmp
对原数组的偶数位下标填充tmp的末尾元素
对原数组的奇数位下标填充tmp的末尾元素
算法复杂度是快速排序的复杂度O(NlogN)。
void wiggleSort(vector<int>& nums) {
int sz = nums.size();
sort(nums.begin(), nums.end());
vector<int> tmp = nums;
int k = sz - 1;
for (int i=1; i<sz; i+=2)
nums[i] = tmp[k--];
for (int i=0; i<sz; i+=2)
nums[i] = tmp[k--];
}
解法II O(n)时间复杂度+O(1)空间复杂度解法:
使用O(n)时间复杂度的quickSelect算法,从未经排序的数组nums中选出中位数mid
参照解法I的思路,将nums数组的下标x通过函数idx()从[0, 1, 2, … , n - 1, n] 映射到 [1, 3, 5, … , 0, 2, 4, …],得到新下标ix
以中位数mid为界,将大于mid的元素排列在ix的较小部分,而将小于mid的元素排列在ix的较大部分。
思路来源:https://discuss.leetcode.com/topic/32929/o-n-o-1-after-median-virtual-indexing
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++;
}
}
3-way-partition
伪码:
procedure three-way-partition(A : array of values, mid : value):
i ← 0
j ← 0
n ← size of A - 1
while j ≤ n:
if A[j] < mid:
swap A[i] and A[j]
i ← i + 1
j ← j + 1
else if A[j] > mid:
swap A[j] and A[n]
n ← n - 1
else:
j ← j + 1